<?php

namespace AIPT\Api\PromptTemplates;

use AIPT\Api\Traits\PromptDataValidatorTrait;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

class PromptTemplateController {

    use PromptDataValidatorTrait;

    /**
     * @var string
     */
    private $table_name;

    /**
     * @var string[]
     */
    private $allowed_sources = [
        'local',
        'community',
    ];

    public function __construct() {
        global $wpdb;
        $this->table_name = $wpdb->prefix . 'aipt_prompt_templates';
    }

    public function register_routes() {
        register_rest_route('aipt/v1', '/prompt-templates', [
            [
                'methods' => 'GET',
                'callback' => [ $this, 'list_templates' ],
                'permission_callback' => [ $this, 'check_permissions' ],
                'args' => [
                    'generator_type' => [
                        'required' => false,
                        'sanitize_callback' => 'sanitize_text_field',
                    ],
                    'source' => [
                        'required' => false,
                        'sanitize_callback' => 'sanitize_text_field',
                    ],
                ],
            ],
            [
                'methods' => 'POST',
                'callback' => [ $this, 'create_template' ],
                'permission_callback' => [ $this, 'check_permissions_write' ],
            ],
        ]);

        register_rest_route('aipt/v1', '/prompt-templates/(?P<id>\d+)', [
            [
                'methods' => 'GET',
                'callback' => [ $this, 'get_template' ],
                'permission_callback' => [ $this, 'check_permissions' ],
                'args' => [
                    'id' => [
                        'required' => true,
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ],
            [
                'methods' => 'PUT',
                'callback' => [ $this, 'update_template' ],
                'permission_callback' => [ $this, 'check_permissions_write' ],
                'args' => [
                    'id' => [
                        'required' => true,
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ],
            [
                'methods' => 'DELETE',
                'callback' => [ $this, 'delete_template' ],
                'permission_callback' => [ $this, 'check_permissions_write' ],
                'args' => [
                    'id' => [
                        'required' => true,
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ],
        ]);

        register_rest_route('aipt/v1', '/prompt-templates/(?P<id>\d+)/set-default', [
            [
                'methods' => 'POST',
                'callback' => [ $this, 'set_default_template' ],
                'permission_callback' => [ $this, 'check_permissions_write' ],
                'args' => [
                    'id' => [
                        'required' => true,
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ],
        ]);

    }

    public function check_permissions( $request ) {
        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            return new WP_Error(
                'rest_forbidden',
                __( 'You do not have permission to access this resource.', 'ai-product-tools' ),
                [ 'status' => 403 ]
            );
        }

        return true;
    }

    public function check_permissions_write( $request ) {
        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            return new WP_Error(
                'rest_forbidden',
                __( 'You do not have permission to perform this action.', 'ai-product-tools' ),
                [ 'status' => 403 ]
            );
        }

        $nonce = $request instanceof \WP_REST_Request ? $request->get_header( 'X-WP-Nonce' ) : '';
        if ( empty( $nonce ) && isset( $_REQUEST['_wpnonce'] ) ) {
            $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) );
        }

        if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
            return new WP_Error(
                'rest_invalid_nonce',
                __( 'Invalid or missing security nonce.', 'ai-product-tools' ),
                [ 'status' => 403 ]
            );
        }

        return true;
    }

    public function list_templates( WP_REST_Request $request ) {
        global $wpdb;

        $generator_type = sanitize_text_field( (string) $request->get_param( 'generator_type' ) );
        $source = sanitize_text_field( (string) $request->get_param( 'source' ) );

        if ( ! empty( $generator_type ) && ! $this->is_valid_generator_type( $generator_type ) ) {
            return new WP_Error(
                'invalid_generator_type',
                __( 'Invalid generator_type value.', 'ai-product-tools' ),
                [ 'status' => 400 ]
            );
        }

        if ( ! empty( $source ) && ! in_array( $source, $this->allowed_sources, true ) ) {
            return new WP_Error(
                'invalid_source',
                __( 'Invalid source value.', 'ai-product-tools' ),
                [ 'status' => 400 ]
            );
        }

        $sql = "SELECT * FROM {$this->table_name}";
        $where = [];
        $values = [];

        if ( ! empty( $generator_type ) ) {
            $where[] = 'generator_type = %s';
            $values[] = $generator_type;
        }

        if ( ! empty( $source ) ) {
            $where[] = 'source = %s';
            $values[] = $source;
        }

        if ( ! empty( $where ) ) {
            $sql .= ' WHERE ' . implode( ' AND ', $where );
        }

        $sql .= ' ORDER BY is_default DESC, created_at DESC';

        if ( ! empty( $values ) ) {

            $sql = $wpdb->prepare( $sql, $values );
        }

        $rows = $wpdb->get_results( $sql, ARRAY_A );
        $items = [];

        foreach ( (array) $rows as $row ) {
            $items[] = $this->prepare_template_response_row( $row );
        }

        return new WP_REST_Response([
            'success' => true,
            'data' => $items,
        ], 200);
    }

    public function get_template( WP_REST_Request $request ) {
        $template_id = absint( $request->get_param( 'id' ) );
        $template = $this->get_template_by_id( $template_id );

        if ( ! $template ) {
            return new WP_Error(
                'template_not_found',
                __( 'Prompt template not found.', 'ai-product-tools' ),
                [ 'status' => 404 ]
            );
        }

        return new WP_REST_Response([
            'success' => true,
            'data' => $template,
        ], 200);
    }

    public function create_template( WP_REST_Request $request ) {
        global $wpdb;

        $validated = $this->validate_template_payload( $request, false );
        if ( is_wp_error( $validated ) ) {
            return $validated;
        }

        if ( ! empty( $validated['is_default'] ) ) {

            $wpdb->update(
                $this->table_name,
                [ 'is_default' => 0 ],
                [
                    'generator_type' => $validated['generator_type'],
                    'is_default' => 1,
                ],
                [ '%d' ],
                [ '%s', '%d' ]
            );
        }

        $inserted = $wpdb->insert(
            $this->table_name,
            [
                'name' => $validated['name'],
                'description' => $validated['description'],
                'generator_type' => $validated['generator_type'],
                'prompt_data' => $validated['prompt_data_json'],
                'wizard_state' => $validated['wizard_state_json'],
                'is_default' => (int) $validated['is_default'],
                'source' => $validated['source'],
                'community_id' => $validated['community_id'],
                'created_at' => current_time( 'mysql' ),
                'updated_at' => current_time( 'mysql' ),
            ],
            [ '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%s', '%s', '%s' ]
        );

        if ( false === $inserted ) {
            return new WP_Error(
                'template_create_failed',
                __( 'Failed to create prompt template.', 'ai-product-tools' ),
                [ 'status' => 500 ]
            );
        }

        $new_template = $this->get_template_by_id( (int) $wpdb->insert_id );

        return new WP_REST_Response([
            'success' => true,
            'data' => $new_template,
        ], 200);
    }

    public function update_template( WP_REST_Request $request ) {
        global $wpdb;

        $template_id = absint( $request->get_param( 'id' ) );
        $existing = $this->get_template_by_id( $template_id );

        if ( ! $existing ) {
            return new WP_Error(
                'template_not_found',
                __( 'Prompt template not found.', 'ai-product-tools' ),
                [ 'status' => 404 ]
            );
        }

        $validated = $this->validate_template_payload( $request, true, $existing );
        if ( is_wp_error( $validated ) ) {
            return $validated;
        }

        if ( ! empty( $validated['is_default'] ) ) {

            $wpdb->update(
                $this->table_name,
                [ 'is_default' => 0 ],
                [
                    'generator_type' => $validated['generator_type'],
                    'is_default' => 1,
                ],
                [ '%d' ],
                [ '%s', '%d' ]
            );
        }

        $updated = $wpdb->update(
            $this->table_name,
            [
                'name' => $validated['name'],
                'description' => $validated['description'],
                'generator_type' => $validated['generator_type'],
                'prompt_data' => $validated['prompt_data_json'],
                'wizard_state' => $validated['wizard_state_json'],
                'is_default' => (int) $validated['is_default'],
                'source' => $validated['source'],
                'community_id' => $validated['community_id'],
                'updated_at' => current_time( 'mysql' ),
            ],
            [ 'id' => $template_id ],
            [ '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%s', '%s' ],
            [ '%d' ]
        );

        if ( false === $updated ) {
            return new WP_Error(
                'template_update_failed',
                __( 'Failed to update prompt template.', 'ai-product-tools' ),
                [ 'status' => 500 ]
            );
        }

        return new WP_REST_Response([
            'success' => true,
            'data' => $this->get_template_by_id( $template_id ),
        ], 200);
    }

    public function delete_template( WP_REST_Request $request ) {
        global $wpdb;

        $template_id = absint( $request->get_param( 'id' ) );
        $existing = $this->get_template_by_id( $template_id );

        if ( ! $existing ) {
            return new WP_Error(
                'template_not_found',
                __( 'Prompt template not found.', 'ai-product-tools' ),
                [ 'status' => 404 ]
            );
        }

        $deleted = $wpdb->delete( $this->table_name, [ 'id' => $template_id ], [ '%d' ] );

        if ( false === $deleted ) {
            return new WP_Error(
                'template_delete_failed',
                __( 'Failed to delete prompt template.', 'ai-product-tools' ),
                [ 'status' => 500 ]
            );
        }

        return new WP_REST_Response([
            'success' => true,
            'data' => [
                'deleted' => true,
                'id' => $template_id,
            ],
        ], 200);
    }

    public function set_default_template( WP_REST_Request $request ) {
        global $wpdb;

        $template_id = absint( $request->get_param( 'id' ) );
        $template = $this->get_template_by_id( $template_id );

        if ( ! $template ) {
            return new WP_Error(
                'template_not_found',
                __( 'Prompt template not found.', 'ai-product-tools' ),
                [ 'status' => 404 ]
            );
        }

        $result = $wpdb->query(
            $wpdb->prepare(
                "UPDATE {$this->table_name}
                SET is_default = CASE WHEN id = %d THEN 1 ELSE 0 END,
                    updated_at = CASE WHEN id = %d THEN %s ELSE updated_at END
                WHERE generator_type = %s",
                $template_id,
                $template_id,
                current_time( 'mysql' ),
                $template['generator_type']
            )
        );

        if ( false === $result ) {
            return new WP_Error(
                'set_default_failed',
                __( 'Failed to set template as default.', 'ai-product-tools' ),
                [ 'status' => 500 ]
            );
        }

        return new WP_REST_Response([
            'success' => true,
            'data' => $this->get_template_by_id( $template_id ),
        ], 200);
    }

    /**
     * @param WP_REST_Request $request
     * @param bool            $is_update
     * @param array<string,mixed> $existing
     * @return array<string,mixed>|WP_Error
     */
    private function validate_template_payload( WP_REST_Request $request, bool $is_update = false, array $existing = [] ) {
        $payload = $request->get_json_params();
        if ( ! is_array( $payload ) ) {
            $payload = [];
        }

        $name = $payload['name'] ?? ( $existing['name'] ?? '' );
        $name = sanitize_text_field( (string) $name );
        if ( '' === $name || strlen( $name ) > 255 ) {
            return new WP_Error(
                'invalid_name',
                __( 'Template name is required and must be 255 characters or less.', 'ai-product-tools' ),
                [ 'status' => 400 ]
            );
        }

        $description = $payload['description'] ?? ( $existing['description'] ?? null );
        if ( null !== $description ) {
            $description = sanitize_textarea_field( (string) $description );
        }

        $generator_type = $payload['generator_type'] ?? ( $existing['generator_type'] ?? '' );
        $generator_type = sanitize_text_field( (string) $generator_type );
        if ( ! $this->is_valid_generator_type( $generator_type ) ) {
            return new WP_Error(
                'invalid_generator_type',
                __( 'Invalid generator_type value.', 'ai-product-tools' ),
                [ 'status' => 400 ]
            );
        }

        $source = $payload['source'] ?? ( $existing['source'] ?? 'local' );
        $source = sanitize_text_field( (string) $source );
        if ( '' === $source ) {
            $source = 'local';
        }
        if ( ! in_array( $source, $this->allowed_sources, true ) ) {
            return new WP_Error(
                'invalid_source',
                __( 'Invalid source value.', 'ai-product-tools' ),
                [ 'status' => 400 ]
            );
        }

        $community_id = $payload['community_id'] ?? ( $existing['community_id'] ?? null );
        if ( null !== $community_id && '' !== $community_id ) {
            $community_id = sanitize_text_field( (string) $community_id );
            if ( strlen( $community_id ) > 36 ) {
                return new WP_Error(
                    'invalid_community_id',
                    __( 'community_id cannot exceed 36 characters.', 'ai-product-tools' ),
                    [ 'status' => 400 ]
                );
            }
        } else {
            $community_id = null;
        }

        if ( array_key_exists( 'prompt_data', $payload ) ) {
            $prompt_data = $payload['prompt_data'];
        } elseif ( $is_update && isset( $existing['prompt_data'] ) ) {
            $prompt_data = $existing['prompt_data'];
        } else {
            $prompt_data = null;
        }

        $validated_prompt_data = $this->validate_prompt_data( $prompt_data, $generator_type );
        if ( is_wp_error( $validated_prompt_data ) ) {
            return $validated_prompt_data;
        }

        if ( array_key_exists( 'wizard_state', $payload ) ) {
            $wizard_state = $payload['wizard_state'];
        } elseif ( $is_update && array_key_exists( 'wizard_state', $existing ) ) {
            $wizard_state = $existing['wizard_state'];
        } else {
            $wizard_state = null;
        }

        if ( null !== $wizard_state && ! is_array( $wizard_state ) ) {
            return new WP_Error(
                'invalid_wizard_state',
                __( 'wizard_state must be an object or array.', 'ai-product-tools' ),
                [ 'status' => 400 ]
            );
        }

        if ( is_array( $wizard_state ) ) {
            $wizard_state = $this->sanitize_wizard_state_recursive( $wizard_state );
        }

        $is_default = isset( $payload['is_default'] )
            ? (int) (bool) $payload['is_default']
            : (int) ( $existing['is_default'] ?? 0 );

        return [
            'name' => $name,
            'description' => $description,
            'generator_type' => $generator_type,
            'prompt_data_json' => wp_json_encode( $validated_prompt_data ),
            'wizard_state_json' => null === $wizard_state ? null : wp_json_encode( $wizard_state ),
            'is_default' => $is_default,
            'source' => $source,
            'community_id' => $community_id,
        ];
    }

    /**
     * @param int $template_id
     * @return array<string,mixed>|null
     */
    private function get_template_by_id( int $template_id ): ?array {
        global $wpdb;

        if ( $template_id <= 0 ) {
            return null;
        }

        $row = $wpdb->get_row(
            $wpdb->prepare( "SELECT * FROM {$this->table_name} WHERE id = %d", $template_id ),
            ARRAY_A
        );

        if ( ! is_array( $row ) ) {
            return null;
        }

        return $this->prepare_template_response_row( $row );
    }

    /**
     * Recursively sanitize wizard_state payload so nested user-supplied strings
     * are cleaned before being persisted to the database.
     *
     * @param array<int|string,mixed> $data
     * @return array<int|string,mixed>
     */
    private function sanitize_wizard_state_recursive( array $data ): array {
        $sanitized = [];
        foreach ( $data as $key => $value ) {
            $clean_key = is_string( $key ) ? sanitize_key( $key ) : $key;
            if ( is_array( $value ) ) {
                $sanitized[ $clean_key ] = $this->sanitize_wizard_state_recursive( $value );
            } elseif ( is_string( $value ) ) {
                $sanitized[ $clean_key ] = sanitize_textarea_field( $value );
            } elseif ( is_int( $value ) || is_float( $value ) || is_bool( $value ) || null === $value ) {
                $sanitized[ $clean_key ] = $value;
            } else {
                $sanitized[ $clean_key ] = null;
            }
        }
        return $sanitized;
    }

    /**
     * @param array<string,mixed> $row
     * @return array<string,mixed>
     */
    private function prepare_template_response_row( array $row ): array {
        $decoded_prompt_data  = json_decode( (string) $row['prompt_data'], true );
        $decoded_wizard_state = json_decode( (string) ( $row['wizard_state'] ?? '' ), true );

        $row['prompt_data'] = is_array( $decoded_prompt_data ) ? $decoded_prompt_data : [];
        $row['wizard_state'] = is_array( $decoded_wizard_state ) ? $decoded_wizard_state : null;
        $row['id'] = (int) $row['id'];
        $row['is_default'] = (int) $row['is_default'];

        return $row;
    }

}
