<?php

namespace AIPT\Api\TaxonomyGenerator;

use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

class TaxonomyGeneratorController {
    use \AIPT\Api\Traits\RateLimitTrait;

    private TaxonomyDiscoveryService $discovery_service;

    private TaxonomyGeneratorService $service;

    public function __construct(
        ?TaxonomyDiscoveryService $discovery_service = null,
        ?TaxonomyGeneratorService $service = null
    ) {
        $this->discovery_service = $discovery_service ?: new TaxonomyDiscoveryService();
        $this->service           = $service ?: new TaxonomyGeneratorService( $this->discovery_service );
    }

    public function register_routes(): void {

        register_rest_route(
            'aipt/v1',
            '/taxonomy-generator/discover-taxonomies',
            [
                'methods' => 'GET',
                'callback' => [$this, 'discover_taxonomies'],
                'permission_callback' => [$this, 'check_permissions'],
            ]
        );

        register_rest_route(
            'aipt/v1',
            '/taxonomy-generator/terms',
            [
                'methods' => 'GET',
                'callback' => [$this, 'get_terms'],
                'permission_callback' => [$this, 'check_permissions'],
                'args' => [
                    'taxonomy' => [
                        'type' => 'string',
                        'required' => true,
                    ],
                ],
            ]
        );

        register_rest_route(
            'aipt/v1',
            '/taxonomy-generator/generate',
            [
                'methods' => 'POST',
                'callback' => [$this, 'generate'],
                'permission_callback' => [$this, 'check_permissions_write'],
                'args' => [
                    'taxonomy' => [
                        'type' => 'string',
                        'required' => true,
                    ],
                    'term_ids' => [
                        'type' => 'array',
                        'required' => true,
                    ],
                    'sources' => [
                        'type' => 'array',
                        'required' => false,
                    ],
                    'options' => [
                        'type' => 'object',
                        'required' => false,
                    ],
                ],
            ]
        );

        register_rest_route(
            'aipt/v1',
            '/taxonomy-generator/apply',
            [
                'methods' => 'POST',
                'callback' => [$this, 'apply'],
                'permission_callback' => [$this, 'check_permissions_write'],
                'args' => [
                    'applications' => [
                        'type' => 'array',
                        'required' => true,
                    ],
                ],
            ]
        );
    }

    public function check_permissions(): bool {
        return current_user_can('manage_woocommerce');
    }

    public function check_permissions_write(): bool {
        return current_user_can('manage_woocommerce');
    }

    /**
     * Discover available taxonomies.
     *
     * @param WP_REST_Request $request REST request instance.
     * @return WP_REST_Response|WP_Error Taxonomy list or error.
     */
    public function discover_taxonomies(WP_REST_Request $request) {
        try {
            $taxonomies = $this->discovery_service->discoverTaxonomies();

            return new WP_REST_Response(
                [
                    'success' => true,
                    'data' => $taxonomies,
                ],
                200
            );
        } catch (\Throwable $throwable) {
            return new WP_Error(
                'taxonomy_discovery_failed',
                sanitize_text_field($throwable->getMessage()),
                ['status' => 500]
            );
        }
    }

    /**
     * Get terms for a given taxonomy.
     *
     * @param WP_REST_Request $request REST request instance.
     * @return WP_REST_Response|WP_Error Terms list or error.
     */
    public function get_terms(WP_REST_Request $request) {
        $taxonomy = (string) sanitize_key((string) $request->get_param('taxonomy'));

        if ('' === $taxonomy) {
            return new WP_Error(
                'invalid_taxonomy',
                __('Taxonomy is required.', 'ai-product-tools'),
                ['status' => 400]
            );
        }

        $args = [
            'search' => sanitize_text_field((string) ($request->get_param('search') ?? '')),
            'page' => absint($request->get_param('page') ?? 1),
            'per_page' => absint($request->get_param('per_page') ?? 50),
            'hide_empty' => $request->get_param('hide_empty') !== null ? (bool) $request->get_param('hide_empty') : false,
        ];

        try {
            $result = $this->discovery_service->getTerms($taxonomy, $args);

            $per_page    = $result['per_page'] ?? 0;
            $total       = $result['total'] ?? 0;
            $total_pages = $per_page > 0 ? (int) ceil( $total / $per_page ) : 0;

            return new WP_REST_Response(
                [
                    'success'    => true,
                    'data'       => $result['terms'] ?? [],
                    'pagination' => [
                        'total'       => $total,
                        'page'        => $result['page'] ?? 1,
                        'per_page'    => $per_page,
                        'total_pages' => $total_pages,
                    ],
                ],
                200
            );
        } catch (\Throwable $throwable) {
            return new WP_Error(
                'taxonomy_terms_failed',
                sanitize_text_field($throwable->getMessage()),
                ['status' => 500]
            );
        }
    }

    /**
     * Generate AI-powered taxonomy descriptions.
     *
     * @param WP_REST_Request $request REST request instance.
     * @return WP_REST_Response|WP_Error Generation results or error.
     */
    public function generate(WP_REST_Request $request) {

        $taxonomy = (string) sanitize_key((string) $request->get_param('taxonomy'));
        $term_ids = array_map('absint', (array) ($request->get_param('term_ids') ?? []));
		$term_ids = array_values( array_filter( $term_ids, function ( $id ) { return $id > 0; } ) );

        if ('' === $taxonomy) {
            return new WP_Error(
                'invalid_taxonomy',
                __('Taxonomy is required.', 'ai-product-tools'),
                ['status' => 400]
            );
        }

        if (empty($term_ids)) {
            return new WP_Error(
                'invalid_terms',
                __('At least one term must be selected.', 'ai-product-tools'),
                ['status' => 400]
            );
        }

        $rate_check = $this->checkRateLimit((int) get_current_user_id(), 'taxonomy', 30, 60);
        if (!$rate_check['allowed']) {
            return $this->rateLimitResponse($rate_check);
        }

        $raw_sources = (array) ($request->get_param('sources') ?? ['term_name']);
        $sources = array_values(array_unique(array_filter(
            array_map(function ($s) {
                return is_string($s) ? trim(sanitize_text_field($s)) : '';
            }, $raw_sources)
        )));
        if (empty($sources)) {
            $sources = ['term_name'];
        }

        $raw_options = (array) ($request->get_param('options') ?? []);
        $allowed_option_keys = [
            'purpose', 'customPurpose', 'tone', 'language', 'length', 'format',
            'provider', 'model', 'temperature', 'maxProductSamples',
            'skipExisting', 'writeMode', 'additionalPrompt',
        ];
        $options = [];
        foreach ($allowed_option_keys as $key) {
            if (!isset($raw_options[$key])) {
                continue;
            }
            $val = $raw_options[$key];
            if (is_string($val)) {
                $options[$key] = sanitize_text_field($val);
            } elseif (is_numeric($val)) {
                $options[$key] = $val;
            } elseif (is_bool($val)) {
                $options[$key] = $val;
            }
        }

        try {
            $result = $this->service->generate($term_ids, $taxonomy, $sources, $options);

            return new WP_REST_Response(
                array_merge(
                    ['success' => true],
                    $result
                ),
                200
            );
        } catch (\Throwable $throwable) {
            return new WP_Error(
                'taxonomy_generation_failed',
                sanitize_text_field($throwable->getMessage()),
                ['status' => 500]
            );
        }
    }

    /**
     * Apply generated descriptions to taxonomy terms.
     *
     * @param WP_REST_Request $request REST request instance.
     * @return WP_REST_Response|WP_Error Applied results or error.
     */
    public function apply(WP_REST_Request $request) {
        $raw_applications = (array) ($request->get_param('applications') ?? []);

        if (empty($raw_applications)) {
            return new WP_Error(
                'invalid_applications',
                __('Applications payload is required.', 'ai-product-tools'),
                ['status' => 400]
            );
        }

        $applications = [];
        foreach ($raw_applications as $item) {
            if (!is_array($item)) {
                continue;
            }
            if (!isset($item['term_id']) || !is_numeric($item['term_id'])) {
                continue;
            }
            if (!isset($item['content'])) {
                continue;
            }
            $applications[] = [
                'term_id'   => absint($item['term_id']),
                'taxonomy'  => isset($item['taxonomy']) ? sanitize_key((string) $item['taxonomy']) : '',
                'content'   => wp_kses_post((string) $item['content']),
                'writeMode' => isset($item['writeMode']) && in_array($item['writeMode'], ['overwrite', 'append'], true) ? $item['writeMode'] : 'overwrite',
            ];
        }

        if (empty($applications)) {
            return new WP_Error(
                'invalid_applications',
                __('No valid application items found.', 'ai-product-tools'),
                ['status' => 400]
            );
        }

        try {
            $result = $this->service->applyDescriptions($applications);

            $applied = 0;
            $errors  = [];

            foreach ( $result as $item ) {
                if ( ! empty( $item['success'] ) ) {
                    $applied++;
                } else {
                    $errors[] = [
                        'term_id' => $item['term_id'] ?? 0,
                        'message' => $item['message'] ?? __( 'Unknown error.', 'ai-product-tools' ),
                    ];
                }
            }

            return new WP_REST_Response(
                [
                    'success' => true,
                    'applied' => $applied,
                    'errors'  => $errors,
                ],
                200
            );
        } catch (\Throwable $throwable) {
            return new WP_Error(
                'taxonomy_apply_failed',
                sanitize_text_field($throwable->getMessage()),
                ['status' => 500]
            );
        }
    }
}
