<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class Niwa_AI_Text_Normalizer {
    public static function normalize( $text, $options = array() ) {
        $options = is_array( $options ) ? $options : array();
        $text    = self::coerce_utf8( $text );
        if ( '' === $text ) {
            return '';
        }

        $text = self::strip_utf8_bom( $text );
        $text = str_replace( "\0", '', $text );
        $text = str_replace( array( "\r\n", "\r" ), "\n", $text );

        if ( empty( $options['preserve_newlines'] ) ) {
            $text = str_replace( "\n", ' ', $text );
        } else {
            $text = preg_replace( "/\n{3,}/", "\n\n", $text );
        }

        if ( ! array_key_exists( 'collapse_whitespace', $options ) || ! empty( $options['collapse_whitespace'] ) ) {
            $collapsed = preg_replace( '/[^\S\n]+/u', ' ', $text );
            if ( null === $collapsed ) {
                $collapsed = preg_replace( '/[^\S\n]+/', ' ', $text );
            }
            $text = is_string( $collapsed ) ? $collapsed : $text;

            if ( empty( $options['preserve_newlines'] ) ) {
                $text = preg_replace( '/\s+/u', ' ', $text );
                if ( null === $text ) {
                    $text = preg_replace( '/\s+/', ' ', (string) $collapsed );
                }
            }
        }

        if ( ! array_key_exists( 'trim', $options ) || ! empty( $options['trim'] ) ) {
            $text = trim( (string) $text );
        }

        return (string) $text;
    }

    public static function normalize_document( $text ) {
        return self::normalize(
            $text,
            array(
                'preserve_newlines' => true,
                'collapse_whitespace' => true,
                'trim' => true,
            )
        );
    }

    public static function normalize_inline( $text ) {
        $text = self::normalize_document( $text );
        if ( '' === $text ) {
            return '';
        }

        $collapsed = preg_replace( '/\s+/u', ' ', $text );
        if ( null === $collapsed ) {
            $collapsed = preg_replace( '/\s+/', ' ', $text );
        }

        return trim( (string) $collapsed );
    }

    public static function split_lines( $text, $trim = false ) {
        $text = self::normalize_document( $text );
        if ( '' === $text ) {
            return array();
        }

        $lines = explode( "\n", $text );
        if ( $trim ) {
            $lines = array_map( 'trim', $lines );
        }

        return $lines;
    }

    public static function is_valid_utf8( $text ) {
        $text = (string) $text;
        if ( '' === $text ) {
            return true;
        }

        if ( function_exists( 'mb_check_encoding' ) ) {
            return mb_check_encoding( $text, 'UTF-8' );
        }

        return false !== preg_match( '//u', $text );
    }

    public static function normalize_file_contents( $path, $rewrite = true ) {
        $path = trim( (string) $path );
        if ( '' === $path || ! file_exists( $path ) || ! is_readable( $path ) ) {
            return array(
                'success' => false,
                'content' => '',
            );
        }

        $raw = file_get_contents( $path );
        if ( false === $raw ) {
            return array(
                'success' => false,
                'content' => '',
            );
        }

        $normalized = self::normalize(
            $raw,
            array(
                'preserve_newlines' => true,
                'collapse_whitespace' => false,
                'trim' => false,
            )
        );
        $updated    = false;

        if ( $rewrite && (string) $raw !== $normalized ) {
            $updated = false !== @file_put_contents( $path, $normalized, LOCK_EX );
        }

        return array(
            'success' => true,
            'content' => $normalized,
            'updated' => $updated,
        );
    }

    private static function coerce_utf8( $text ) {
        $text = (string) $text;
        if ( '' === $text || self::is_valid_utf8( $text ) ) {
            return $text;
        }

        $candidates = array();

        if ( function_exists( 'iconv' ) ) {
            foreach ( array(
                array( 'from' => 'UTF-8', 'to' => 'UTF-8//IGNORE' ),
                array( 'from' => 'Windows-1252', 'to' => 'UTF-8//IGNORE' ),
                array( 'from' => 'ISO-8859-1', 'to' => 'UTF-8//IGNORE' ),
            ) as $mapping ) {
                $converted = @iconv( $mapping['from'], $mapping['to'], $text );
                if ( is_string( $converted ) && '' !== $converted ) {
                    $candidates[] = $converted;
                }
            }
        }

        if ( function_exists( 'mb_convert_encoding' ) ) {
            $encodings = array( 'UTF-8', 'Windows-1252', 'ISO-8859-1' );
            $detected  = function_exists( 'mb_detect_encoding' )
                ? @mb_detect_encoding( $text, $encodings, true )
                : false;

            if ( is_string( $detected ) && '' !== $detected ) {
                $converted = @mb_convert_encoding( $text, 'UTF-8', $detected );
                if ( is_string( $converted ) && '' !== $converted ) {
                    $candidates[] = $converted;
                }
            }

            foreach ( array( 'Windows-1252', 'ISO-8859-1' ) as $encoding ) {
                $converted = @mb_convert_encoding( $text, 'UTF-8', $encoding );
                if ( is_string( $converted ) && '' !== $converted ) {
                    $candidates[] = $converted;
                }
            }
        }

        foreach ( $candidates as $candidate ) {
            if ( self::is_valid_utf8( $candidate ) ) {
                return $candidate;
            }
        }

        return ! empty( $candidates ) ? (string) $candidates[0] : $text;
    }

    private static function strip_utf8_bom( $text ) {
        if ( 0 === strpos( (string) $text, "\xEF\xBB\xBF" ) ) {
            return substr( (string) $text, 3 );
        }

        return (string) $text;
    }
}
