<?php

declare(strict_types=1);

namespace BadamSoft\WooProductExporter\Templates;

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

use BadamSoft\WooProductExporter\Access\AccessManager;
use BadamSoft\WooProductExporter\Exporter\Exporter;
use BadamSoft\WooProductExporter\Helpers\DownloadHelper;
use BadamSoft\WooProductExporter\Settings\SettingsRepository;
use BadamSoft\WooProductExporter\Templates\CsvTemplateImporter;
use Throwable;

class TemplateController {
    private TemplateManager $template_manager;
    private Exporter $exporter;
    private CsvTemplateImporter $csv_importer;
    private AccessManager $access_manager;

    public const ACTION_CREATE  = 'prodexfo_template_create';
    public const ACTION_UPDATE  = 'prodexfo_template_update';
    public const ACTION_DELETE  = 'prodexfo_template_delete';
    public const ACTION_EXPORT  = 'prodexfo_template_export';
    public const ACTION_IMPORT  = 'prodexfo_template_import';
    public const ACTION_SELECT  = 'prodexfo_template_select';
    public const ACTION_PREVIEW = 'prodexfo_template_preview';

    public function __construct( TemplateManager $template_manager, Exporter $exporter, AccessManager $access_manager ) {
        $this->template_manager = $template_manager;
        $this->exporter         = $exporter;
        $this->csv_importer     = new CsvTemplateImporter( $template_manager, $exporter );
        $this->access_manager   = $access_manager;

        add_action( 'wp_ajax_' . self::ACTION_CREATE, [ $this, 'handle_create' ] );
        add_action( 'wp_ajax_' . self::ACTION_UPDATE, [ $this, 'handle_update' ] );
        add_action( 'wp_ajax_' . self::ACTION_DELETE, [ $this, 'handle_delete' ] );
        add_action( 'wp_ajax_' . self::ACTION_EXPORT, [ $this, 'handle_export' ] );
        add_action( 'wp_ajax_' . self::ACTION_IMPORT, [ $this, 'handle_import' ] );
        add_action( 'wp_ajax_' . self::ACTION_SELECT, [ $this, 'handle_select' ] );
        add_action( 'wp_ajax_' . self::ACTION_PREVIEW, [ $this, 'handle_preview' ] );
    }

    public function handle_preview(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( [ 'message' => __( 'You do not have permission to preview exports.', 'badamsoft-product-exporter-for-woocommerce' ) ], 403 );
        }

        check_ajax_referer( 'prodexfo_preview_nonce', 'nonce' );

        $raw_post = filter_input_array( INPUT_POST, FILTER_UNSAFE_RAW );
        $request  = is_array( $raw_post ) ? wp_unslash( $raw_post ) : [];

        $fields = $this->exporter->sanitize_fields_from_request( $request );

        if ( empty( $fields ) ) {
            wp_send_json_error( [ 'message' => __( 'Select at least one column to preview.', 'badamsoft-product-exporter-for-woocommerce' ) ], 400 );
        }

        $fields   = $this->applyFieldOrder( $fields, $request );
        $filters  = $this->exporter->sanitize_filters_from_request( $request );
        $settings = $this->exporter->sanitize_settings_from_request( $request );

        $limit = Exporter::PREVIEW_ROW_LIMIT;

        if ( isset( $request['limit'] ) ) {
            $limit = (int) $request['limit'];
            $limit = max( 1, min( $limit, Exporter::PREVIEW_ROW_LIMIT ) );
        }

        try {
            $data = $this->exporter->get_preview_data( $fields, $filters, $limit, $settings );
        } catch ( Throwable $exception ) {
            wp_send_json_error( [ 'message' => __( 'Unable to generate preview.', 'badamsoft-product-exporter-for-woocommerce' ) ], 500 );
        }

        wp_send_json_success(
            [
                'columns'   => $data['columns'],
                'rows'      => $data['rows'],
                'count'     => $data['count'],
                'limit'     => $data['limit'],
                'fields'    => $fields,
                'truncated' => $data['count'] >= $data['limit'],
            ]
        );
    }

    public function handle_create(): void {
        $this->verifyRequest();

        $payload  = $this->buildTemplatePayloadFromRequest();
        $template = $this->template_manager->sanitize_template_payload( $payload );
        $this->template_manager->save_template( $template );

        wp_send_json_success(
            [
                'template' => $this->shapeTemplateForResponse( $template ),
                'data'     => $template,
            ]
        );
    }

    public function handle_update(): void {
        $this->verifyRequest();

        $template_id = $this->getRequestString( 'template_id' );

        if ( ! $template_id ) {
            wp_send_json_error( [ 'message' => __( 'Template ID is required.', 'badamsoft-product-exporter-for-woocommerce' ) ], 400 );
        }

        $existing = $this->template_manager->get_template( $template_id );

        if ( ! $existing ) {
            wp_send_json_error( [ 'message' => __( 'Template not found.', 'badamsoft-product-exporter-for-woocommerce' ) ], 404 );
        }

        $payload               = $this->buildTemplatePayloadFromRequest();
        $payload['id']         = $template_id;
        $payload['created_at'] = $existing['created_at'] ?? $payload['created_at'];

        $template = $this->template_manager->sanitize_template_payload( $payload );
        $this->template_manager->save_template( $template );

        wp_send_json_success(
            [
                'template' => $this->shapeTemplateForResponse( $template ),
                'data'     => $template,
            ]
        );
    }

    public function handle_delete(): void {
        $this->verifyRequest();

        $template_id = $this->getRequestString( 'template_id' );

        if ( ! $template_id ) {
            wp_send_json_error( [ 'message' => __( 'Template ID is required.', 'badamsoft-product-exporter-for-woocommerce' ) ], 400 );
        }

        $deleted = $this->template_manager->delete_template( $template_id );

        if ( $deleted ) {
            $current_user = get_current_user_id();

            if ( $current_user && $this->template_manager->get_selected_template_for_user( $current_user ) === $template_id ) {
                $this->template_manager->set_selected_template_for_user( $current_user, null );
            }
        }

        wp_send_json_success(
            [
                'deleted'     => (bool) $deleted,
                'template_id' => $template_id,
            ]
        );
    }

    public function handle_export(): void {
        $this->verifyRequest();

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'You do not have permission to export products.', 'badamsoft-product-exporter-for-woocommerce' ) );
        }

        $template_id = $this->getRequestString( 'template_id' );

        if ( ! $template_id ) {
            $template_id = $this->getRequestString( 'templateId' );
        }

        if ( ! $template_id ) {
            $template_id = $this->getRequestString( 'id' );
        }

        if ( ! $template_id ) {
            wp_send_json_error( [ 'message' => __( 'Template ID is required.', 'badamsoft-product-exporter-for-woocommerce' ) ], 400 );
        }

        $template = $this->template_manager->get_template( $template_id );

        if ( ! $template ) {
            wp_send_json_error( [ 'message' => __( 'Template not found.', 'badamsoft-product-exporter-for-woocommerce' ) ], 404 );
        }

        $fields = isset( $template['fields'] ) && is_array( $template['fields'] ) && ! empty( $template['fields'] )
            ? array_values( array_filter( array_map( [ $this->exporter, 'sanitize_field_key' ], $template['fields'] ) ) )
            : $this->exporter->get_default_fields();

        if ( empty( $fields ) ) {
            $fields = $this->exporter->get_default_fields();
        }

        $filters  = isset( $template['filters'] ) && is_array( $template['filters'] ) ? $template['filters'] : [];
        $format   = isset( $template['format'] ) ? (string) $template['format'] : '';
        $settings = isset( $template['settings'] ) && is_array( $template['settings'] ) ? $template['settings'] : [];

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

        $upload_dir = wp_upload_dir();

        if ( ! empty( $upload_dir['error'] ) || empty( $upload_dir['basedir'] ) ) {
            wp_die( esc_html__( 'Uploads directory is not writable.', 'badamsoft-product-exporter-for-woocommerce' ) );
        }

        $settings_repository = new SettingsRepository();
        $root_dir            = $settings_repository->resolve_export_root_directory( (string) ( $upload_dir['basedir'] ?? '' ) );
        $base_dir            = trailingslashit( $root_dir . 'templates' );

        if ( ! wp_mkdir_p( $base_dir ) ) {
            wp_die( esc_html__( 'Unable to prepare the export directory.', 'badamsoft-product-exporter-for-woocommerce' ) );
        }

        $resolved_name = $this->exporter->resolve_filename_for_format( $settings, $format );
        $filename      = wp_unique_filename( $base_dir, $resolved_name );
        $file_path     = trailingslashit( $base_dir ) . $filename;

        try {
            $result = $this->exporter->export_to_file( $fields, $filters, $format, $settings, $file_path );
        } catch ( Throwable $exception ) {
            wp_die( esc_html( $exception->getMessage() ) );
        }

        $run_meta = $this->exporter->record_run( $fields, $filters, $format, $result, $template_id, 'manual' );
        do_action( 'prodexfo_export_completed', $fields, $filters, $run_meta );

        if ( ! file_exists( $file_path ) ) {
            wp_die( esc_html__( 'Export file could not be created.', 'badamsoft-product-exporter-for-woocommerce' ) );
        }

        $mtime = filemtime( $file_path );
        DownloadHelper::send_headers( basename( $file_path ), 'application/octet-stream', $mtime ? (int) $mtime : 0 );

        $handle = fopen( $file_path, 'rb' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen

        if ( false === $handle ) {
            wp_die( esc_html__( 'Could not open export file for download.', 'badamsoft-product-exporter-for-woocommerce' ) );
        }

        while ( ! feof( $handle ) ) {
            echo fread( $handle, 8192 ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fread, WordPress.Security.EscapeOutput.OutputNotEscaped
        }

        fclose( $handle ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
        exit;
    }

    public function handle_import(): void {
        $this->verifyRequest();
        check_ajax_referer( 'prodexfo_templates_nonce', 'nonce' );

        $raw_files = wp_unslash( $_FILES );
        $template_file = isset( $raw_files['template_file'] ) ? $raw_files['template_file'] : null;

        if ( ! is_array( $template_file ) || empty( $template_file['tmp_name'] ) ) {
            wp_send_json_error( [ 'message' => __( 'Import file is required.', 'badamsoft-product-exporter-for-woocommerce' ) ], 400 );
        }

        $raw_file = $template_file;

        $file = [
            'name'     => isset( $raw_file['name'] ) ? sanitize_file_name( (string) $raw_file['name'] ) : '',
            'type'     => isset( $raw_file['type'] ) ? sanitize_text_field( (string) $raw_file['type'] ) : '',
            'tmp_name' => isset( $raw_file['tmp_name'] ) ? (string) $raw_file['tmp_name'] : '',
            'error'    => isset( $raw_file['error'] ) ? (int) $raw_file['error'] : 0,
            'size'     => isset( $raw_file['size'] ) ? (int) $raw_file['size'] : 0,
        ];

        if ( ! empty( $file['error'] ) ) {
            wp_send_json_error( [ 'message' => __( 'Unable to upload template file.', 'badamsoft-product-exporter-for-woocommerce' ) ], 400 );
        }

        if ( ! $this->validate_import_file( $file ) ) {
            wp_send_json_error( [ 'message' => __( 'Invalid file type. Only CSV and JSON files are allowed.', 'badamsoft-product-exporter-for-woocommerce' ) ], 400 );
        }

        $contents = file_get_contents( $file['tmp_name'] ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents

        if ( false === $contents ) {
            wp_send_json_error( [ 'message' => __( 'Unable to read template file.', 'badamsoft-product-exporter-for-woocommerce' ) ], 400 );
        }

        $replace_existing_raw = filter_input( INPUT_POST, 'replace_existing', FILTER_UNSAFE_RAW );
        $replace_existing = null !== $replace_existing_raw
            ? (bool) absint( sanitize_text_field( (string) $replace_existing_raw ) )
            : false;
        $templates_data   = $this->csv_importer->parse( $contents, $replace_existing );

        if ( empty( $templates_data ) ) {
            wp_send_json_error( [ 'message' => __( 'Template CSV is empty or invalid.', 'badamsoft-product-exporter-for-woocommerce' ) ], 400 );
        }

        $imported_count     = 0;
        $imported_templates = [];

        foreach ( $templates_data as $raw_template ) {
            if ( ! is_array( $raw_template ) ) {
                continue;
            }

            $template = $this->template_manager->sanitize_template_payload( $raw_template );
            $imported_count++;

            $imported_templates[] = [
                'template' => $this->shapeTemplateForResponse( $template ),
                'data'     => $template,
            ];
        }

        wp_send_json_success(
            [
                'imported'  => $imported_count,
                'templates' => $imported_templates,
            ]
        );
    }

    public function handle_select(): void {
        $this->verifyRequest();

        $template_id = $this->getRequestString( 'template_id' );
        $user_id     = get_current_user_id();

        if ( ! $user_id ) {
            wp_send_json_error( [ 'message' => __( 'User session expired.', 'badamsoft-product-exporter-for-woocommerce' ) ], 400 );
        }

        if ( '' === $template_id ) {
            $this->template_manager->set_selected_template_for_user( $user_id, null );
            wp_send_json_success( [ 'template_id' => '' ] );
        }

        $template = $this->template_manager->get_template( $template_id );

        if ( ! $template ) {
            wp_send_json_error( [ 'message' => __( 'Template not found.', 'badamsoft-product-exporter-for-woocommerce' ) ], 404 );
        }

        $this->template_manager->set_selected_template_for_user( $user_id, $template_id );

        wp_send_json_success(
            [
                'template_id' => $template_id,
                'template'    => $this->shapeTemplateForResponse( $template ),
                'data'        => $template,
            ]
        );
    }

    private function buildTemplatePayloadFromRequest(): array {
        $raw_post = filter_input_array( INPUT_POST, FILTER_UNSAFE_RAW );
        $request  = is_array( $raw_post ) ? wp_unslash( $raw_post ) : [];

        $fields   = $this->exporter->sanitize_fields_from_request( $request );
        $filters  = $this->exporter->sanitize_filters_from_request( $request );
        $format   = $this->exporter->sanitize_format_from_request( $request );
        $settings = $this->exporter->sanitize_settings_from_request( $request );

        return [
            'name'        => $this->getRequestString( 'template_name' ) ?: __( 'Untitled template', 'badamsoft-product-exporter-for-woocommerce' ),
            'description' => sanitize_textarea_field( $request['template_description'] ?? '' ),
            'fields'      => $fields,
            'filters'     => $filters,
            'format'      => $format,
            'settings'    => $settings,
        ];
    }

    private function verifyRequest(): void {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( [ 'message' => __( 'You do not have permission to manage templates.', 'badamsoft-product-exporter-for-woocommerce' ) ], 403 );
        }

        check_ajax_referer( 'prodexfo_templates_nonce', 'nonce' );
    }

    private function getRequestString( string $key ): string {
        $raw_post = filter_input_array( INPUT_POST, FILTER_UNSAFE_RAW );
        $request  = is_array( $raw_post ) ? wp_unslash( $raw_post ) : [];

        if ( empty( $request[ $key ] ) ) {
            return '';
        }

        return sanitize_text_field( (string) $request[ $key ] );
    }

    /**
     * @param array<int, string>     $fields
     * @param array<string, mixed>   $request
     * @return array<int, string>
     */
    private function applyFieldOrder( array $fields, array $request ): array {
        if ( empty( $request['fields_order'] ) ) {
            return $fields;
        }

        $order_input = $request['fields_order'];

        if ( is_string( $order_input ) ) {
            $decoded = json_decode( $order_input, true );
        } elseif ( is_array( $order_input ) ) {
            $decoded = $order_input;
        } else {
            $decoded = null;
        }

        if ( ! is_array( $decoded ) ) {
            return $fields;
        }

        $sanitized_order = array_filter( array_map( [ $this->exporter, 'sanitize_field_key' ], $decoded ) );

        if ( empty( $sanitized_order ) ) {
            return $fields;
        }

        $ordered = [];
        $seen    = [];

        foreach ( $sanitized_order as $key ) {
            if ( in_array( $key, $fields, true ) && ! isset( $seen[ $key ] ) ) {
                $ordered[]    = $key;
                $seen[ $key ] = true;
            }
        }

        foreach ( $fields as $key ) {
            if ( ! isset( $seen[ $key ] ) ) {
                $ordered[]    = $key;
                $seen[ $key ] = true;
            }
        }

        return $ordered;
    }

    /**
     * @param array<string, mixed> $template
     * @return array<string, mixed>
     */
    private function shapeTemplateForResponse( array $template ): array {
        return [
            'id'          => $template['id'] ?? '',
            'name'        => $template['name'] ?? '',
            'description' => $template['description'] ?? '',
            'updated_at'  => $template['updated_at'] ?? '',
        ];
    }

    /**
     * Validate uploaded file for template import.
     *
     * @param array<string, mixed> $file $_FILES array element.
     * @return bool
     */
    private function validate_import_file( array $file ): bool {
        $allowed_types = [ 'application/json', 'text/csv', 'text/plain' ];
        $allowed_extensions = [ 'csv', 'json' ];

        $file_type = isset( $file['type'] ) ? strtolower( $file['type'] ) : '';
        $file_name = isset( $file['name'] ) ? sanitize_file_name( $file['name'] ) : '';
        $extension = strtolower( pathinfo( $file_name, PATHINFO_EXTENSION ) );

        if ( ! in_array( $extension, $allowed_extensions, true ) ) {
            return false;
        }

        if ( ! empty( $file_type ) && ! in_array( $file_type, $allowed_types, true ) ) {
            return false;
        }

        $tmp_name = isset( $file['tmp_name'] ) ? $file['tmp_name'] : '';

        if ( empty( $tmp_name ) || ! is_uploaded_file( $tmp_name ) ) {
            return false;
        }

        return true;
    }
}
