<?php

declare(strict_types=1);

namespace BadamSoft\WooProductExporter\Templates;

use BadamSoft\WooProductExporter\Exporter\Exporter;
use BadamSoft\WooProductExporter\Helpers\Utils;

use function __;
use function array_keys;
use function array_map;
use function array_shift;
use function array_unique;
use function array_values;
use function in_array;
use function json_decode;
use function strtolower;
use function trim;
use function wp_generate_uuid4;

class CsvTemplateImporter {
    private TemplateManager $template_manager;

    private Exporter $exporter;

    /**
     * @var array<string, mixed>
     */
    private array $default_settings;

    private string $default_format;

    /**
     * @var array<string, string>
     */
    private array $field_lookup = [];

    private string $delimiter = ',';

    public function __construct( TemplateManager $template_manager, Exporter $exporter ) {
        $this->template_manager = $template_manager;
        $this->exporter         = $exporter;
        $this->default_settings = $this->template_manager->sanitize_settings_payload( [] );

        $this->default_format = $this->exporter->get_default_format_key();

        if ( '' === $this->default_format ) {
            $this->default_format = 'csv';
        }
    }

    /**
     * Convert CSV contents into sanitized template payloads.
     *
     * @param string $contents
     * @param bool   $replace_existing
     *
     * @return array<int, array<string, mixed>>
     */
    public function parse( string $contents, bool $replace_existing = false ): array {
        $contents = trim( $contents );

        if ( '' === $contents ) {
            return [];
        }

        $lines = preg_split( '/\r\n|\r|\n/', $contents );

        if ( ! is_array( $lines ) || empty( $lines ) ) {
            return [];
        }

        $header_line = '';

        while ( ! empty( $lines ) ) {
            $candidate = array_shift( $lines );

            if ( '' !== trim( (string) $candidate ) ) {
                $header_line = (string) $candidate;
                break;
            }
        }

        if ( '' === $header_line ) {
            return [];
        }

        $this->delimiter = $this->detect_delimiter( $header_line );

        $header = $this->parse_csv_line( $header_line );

        if ( empty( $header ) ) {
            return [];
        }

        $normalized_header = array_map(
            function ( $value ): string {
                return $this->normalize_header_value( (string) $value );
            },
            $header
        );

        if ( $this->looks_like_template_export( $normalized_header ) ) {
            return $this->parse_template_definitions( $normalized_header, $lines, $replace_existing );
        }

        return $this->parse_from_column_header( $header );
    }

    /**
     * @param array<int, string> $normalized_header
     * @param array<int, string> $lines
     *
     * @return array<int, array<string, mixed>>
     */
    private function parse_template_definitions( array $normalized_header, array $lines, bool $replace_existing ): array {
        $existing_ids = array_keys( $this->template_manager->get_templates() );
        $seen_ids     = [];
        $templates    = [];

        foreach ( $lines as $line ) {
            if ( '' === trim( (string) $line ) ) {
                continue;
            }

            $columns = $this->parse_csv_line( $line );

            if ( empty( $columns ) ) {
                continue;
            }

            $row = [];

            foreach ( $normalized_header as $index => $key ) {
                if ( '' === $key ) {
                    continue;
                }

                $row[ $key ] = $columns[ $index ] ?? '';
            }

            $payload = $this->build_template_payload_from_definition_row( $row, $replace_existing, $existing_ids, $seen_ids );

            if ( ! $payload ) {
                continue;
            }

            $templates[]    = $payload;
            $existing_ids[] = $payload['id'];
            $seen_ids[]     = $payload['id'];
        }

        return $templates;
    }

    /**
     * @param array<int, string> $header
     *
     * @return array<int, array<string, mixed>>
     */
    private function parse_from_column_header( array $header ): array {
        $fields = $this->map_fields_from_header( $header );

        if ( empty( $fields ) ) {
            return [];
        }

        $template = [
            'id'          => wp_generate_uuid4(),
            /* translators: %s: import date/time */
            'name'        => sprintf( __( 'Imported template %s', 'badamsoft-product-exporter-for-woocommerce' ), \wp_date( 'Y-m-d H:i' ) ),
            'description' => '',
            'fields'      => $fields,
            'filters'     => [],
            'format'      => $this->default_format,
            'settings'    => $this->default_settings,
        ];

        return [ $template ];
    }

    /**
     * @param array<string, string> $row
     * @param array<int, string>    $existing_ids
     * @param array<int, string>    $seen_ids
     */
    private function build_template_payload_from_definition_row( array $row, bool $replace_existing, array $existing_ids, array $seen_ids ): ?array {
        $raw_id = trim( (string) ( $row['id'] ?? '' ) );
        $id     = $this->resolve_id( $raw_id, $replace_existing, $existing_ids, $seen_ids );

        $fields_raw   = (string) ( $row['fields'] ?? '' );
        $filters_raw  = (string) ( $row['filters'] ?? '' );
        $settings_raw = (string) ( $row['settings'] ?? '' );

        $fields   = $this->decode_json_column( $fields_raw, [] );
        $filters  = $this->decode_json_column( $filters_raw, [] );
        $settings = $this->decode_json_column( $settings_raw, [] );

        if ( ! is_array( $fields ) || ! is_array( $filters ) || ! is_array( $settings ) ) {
            return null;
        }

        if ( empty( $settings ) ) {
            $settings = $this->default_settings;
        }

        $format = (string) ( $row['format'] ?? '' );

        if ( '' === $format ) {
            $format = $this->default_format;
        }

        $payload = [
            'id'          => $id,
            'name'        => (string) ( $row['name'] ?? '' ),
            'description' => (string) ( $row['description'] ?? '' ),
            'fields'      => $fields,
            'filters'     => $filters,
            'format'      => $format,
            'settings'    => $settings,
        ];

        if ( '' !== ( $row['created_at'] ?? '' ) ) {
            $payload['created_at'] = (string) $row['created_at'];
        }

        if ( '' !== ( $row['updated_at'] ?? '' ) ) {
            $payload['updated_at'] = (string) $row['updated_at'];
        }

        return $payload;
    }

    /**
     * @param array<int, string> $header
     *
     * @return array<int, string>
     */
    private function map_fields_from_header( array $header ): array {
        $lookup = $this->get_field_lookup();
        $fields = [];

        foreach ( $header as $column ) {
            $normalized = $this->normalize_header_value( (string) $column );

            if ( '' === $normalized ) {
                continue;
            }

            $normalized = rtrim( $normalized, ':' );

            if ( isset( $lookup[ $normalized ] ) ) {
                $fields[] = $lookup[ $normalized ];
                continue;
            }

            $sanitized = $this->normalize_header_value( Utils::sanitize_field_key( (string) $column ) );

            if ( isset( $lookup[ $sanitized ] ) ) {
                $fields[] = $lookup[ $sanitized ];
            }
        }

        return array_values( array_unique( $fields ) );
    }

    /**
     * @return array<string, string>
     */
    private function get_field_lookup(): array {
        if ( ! empty( $this->field_lookup ) ) {
            return $this->field_lookup;
        }

        $definitions = $this->exporter->get_field_definitions();
        $lookup      = [];

        foreach ( $definitions as $key => $definition ) {
            $candidates = [
                $this->normalize_header_value( $key ),
                $this->normalize_header_value( Utils::sanitize_field_key( $key ) ),
            ];

            if ( isset( $definition['label'] ) ) {
                $candidates[] = $this->normalize_header_value( (string) $definition['label'] );
            }

            foreach ( $candidates as $candidate ) {
                if ( '' === $candidate || isset( $lookup[ $candidate ] ) ) {
                    continue;
                }

                $lookup[ $candidate ] = $key;
            }
        }

        $this->field_lookup = $lookup;

        return $this->field_lookup;
    }

    /**
     * @param array<int, string> $normalized_header
     */
    private function looks_like_template_export( array $normalized_header ): bool {
        $required = [ 'id', 'fields', 'settings' ];

        foreach ( $required as $key ) {
            if ( ! in_array( $key, $normalized_header, true ) ) {
                return false;
            }
        }

        return true;
    }

    private function normalize_header_value( string $value ): string {
        $value = $this->strip_bom( $value );
        $value = strtolower( trim( $value ) );
        $value = str_replace( [ '  ', "\t" ], ' ', $value );

        return trim( $value );
    }

    private function strip_bom( string $value ): string {
        if ( 0 === strpos( $value, "\xEF\xBB\xBF" ) ) {
            return substr( $value, 3 );
        }

        return $value;
    }

    private function detect_delimiter( string $line ): string {
        $candidates = [ ',', ';', "\t", '|' ];
        $best       = ',';
        $best_count = -1;

        foreach ( $candidates as $candidate ) {
            $count = substr_count( $line, $candidate );

            if ( $count > $best_count ) {
                $best       = $candidate;
                $best_count = $count;
            }
        }

        return $best;
    }

    /**
     * @return array<int, string>
     */
    private function parse_csv_line( string $line ): array {
        $entries = str_getcsv( $line, $this->delimiter, '"', '\\' );

        if ( ! is_array( $entries ) ) {
            return [];
        }

        return array_map(
            function ( $value ) {
                return is_string( $value ) ? trim( $this->strip_bom( $value ) ) : '';
            },
            $entries
        );
    }

    /**
     * @param array<int, string> $existing_ids
     * @param array<int, string> $seen_ids
     */
    private function resolve_id( string $raw_id, bool $replace_existing, array $existing_ids, array $seen_ids ): string {
        if ( '' === $raw_id ) {
            return wp_generate_uuid4();
        }

        if ( $replace_existing ) {
            return $raw_id;
        }

        if ( in_array( $raw_id, $existing_ids, true ) || in_array( $raw_id, $seen_ids, true ) ) {
            return wp_generate_uuid4();
        }

        return $raw_id;
    }

    /**
     * @param string $value
     * @param mixed  $default
     *
     * @return mixed
     */
    private function decode_json_column( string $value, $default ) {
        $value = trim( $value );

        if ( '' === $value ) {
            return $default;
        }

        $decoded = json_decode( $value, true );

        if ( null === $decoded && 'null' !== strtolower( $value ) ) {
            return $default;
        }

        return $decoded;
    }
}

