<?php

namespace Licenzo\Http\Controller\Api\V1;

use Licenzo\Framework\Http\Request;
use Licenzo\Model\Product;
use Licenzo\Model\ProductVariation;
use Licenzo\Services\Integrations\ProviderAliasService;

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Product API controller for managing products and their variations
 */
class ProductController
{
    /**
     * List products with optional search and status filters
     */
    public function index(Request $request)
    {
        try {
            $filter = $request->getSafe([
                'search' => 'sanitize_text_field',
                'status' => 'sanitize_text_field',
            ]);

            $query = Product::query()->orderBy('created_at', 'desc');

            if (!empty($filter['search'])) {
                global $wpdb;
                $searchTerm = '%' . $wpdb->esc_like($filter['search']) . '%';
                $query->where(function ($q) use ($searchTerm) {
                    $q->where('name', 'LIKE', $searchTerm)
                        ->orWhere('description', 'LIKE', $searchTerm)
                    ;
                });
            }

            if (!empty($filter['status']) && $filter['status'] !== 'all') {
                $query->where('status', $filter['status']);
            }

            $products = $query->with('variations')->paginate();


            return [
                'success'  => true,
                'products' => $products,
            ];
        } catch (\Throwable $th) {
            return [
                'success' => false,
                'message' => (defined('WP_DEBUG') && WP_DEBUG) ? 'Error fetching products: ' . $th->getMessage() : __('An error occurred', 'licenzo')
            ];
        }
    }

    /**
     * Store a new product
     */
    public function store(Request $request)
    {
        try {
            $data = $request->getSafe([
                'name'                  => 'sanitize_text_field',
                'description'           => 'sanitize_textarea_field',
                'status'                => 'sanitize_text_field',
                'product_id'            => 'sanitize_text_field',
                'source_type'           => 'sanitize_text_field',
                'option_type'           => 'sanitize_text_field',
                'product_link'          => 'sanitize_text_field',
                'provider_product_name' => 'sanitize_text_field',
            ]);

            if (empty($data['name']) || empty($data['status'])) {
                return ['success' => false, 'message' => __('Name and status are required.', 'licenzo')];
            }

            $options = $request->get('options');
            if (empty($options) || !is_array($options)) {
                return ['success' => false, 'message' => __('At least one variation is required.', 'licenzo')];
            }
            // Sanitize each option
            $options = $this->sanitizeOptions($options);

            $optionValidationError = $this->validateOptionMappings($options, $data);
            if (!empty($optionValidationError)) {
                return ['success' => false, 'message' => $optionValidationError];
            }

            $error = $this->checkUniqueness($data);
            if ($error) return ['success' => false, 'message' => $error];

            $product = Product::create([
                'uuid'                  => wp_generate_uuid4(),
                'name'                  => $data['name'],
                'slug'                  => sanitize_title($data['name']),
                'description'           => $data['description'] ?? null,
                'status'                => $data['status'],
                'provider_id'  => !empty($data['product_id']) ? (string) $data['product_id'] : null,
                'provider'              => $data['source_type'] == "provider"
                    ? Product::PROVIDER_WOOCOMMERCE
                    : ProviderAliasService::normalize((string) ($data['source_type'] ?? ''), Product::PROVIDER_MANUAL),
                'type'                  => $data['option_type'] ?? 'single',
                'provider_product_name' => $data['provider_product_name'] ?? null,
                'product_link'          => $data['product_link'] ?? null,
            ]);

            // Sync options
            $variations = $this->syncOptions($options, $product);

            return ['success' => true, 'message' => __('Product created successfully', 'licenzo'), 'product' => $product, 'variations' => $variations];
        } catch (\Throwable $th) {
            return ['success' => false, 'message' => (defined('WP_DEBUG') && WP_DEBUG) ? 'Error creating product: ' . $th->getMessage() : __('An error occurred', 'licenzo')];
        }
    }

    /**
     * Show a product by ID
     */
    public function show($id)
    {
        $product = Product::with('variations')->find($id);

        if (!$product) {
            return ['success' => false, 'message' => __('Product not found.', 'licenzo')];
        }

        return [
            'success' => true,
            'product' => $product
        ];
    }

    /**
     * Update a product
     */
    public function update(Request $request, $id)
    {
        try {
            $product = Product::find($id);
            if (!$product) return ['success' => false, 'message' => __('Product not found.', 'licenzo')];

            $data = $request->getSafe([
                'name'                  => 'sanitize_text_field',
                'description'           => 'sanitize_textarea_field',
                'status'                => 'sanitize_text_field',
                'product_id'            => 'sanitize_text_field',
                'option_type'           => 'sanitize_text_field',
                'product_link'          => 'sanitize_text_field',
                'provider_product_name' => 'sanitize_text_field',
            ]);


            $options = $request->get('options');
            if (empty($options) || !is_array($options)) {
                return ['success' => false, 'message' => __('At least one option is required.', 'licenzo')];
            }
            // Sanitize each option
            $options = $this->sanitizeOptions($options);

            $optionValidationError = $this->validateOptionMappings($options, $data, $product);
            if (!empty($optionValidationError)) {
                return ['success' => false, 'message' => $optionValidationError];
            }

            $error = $this->checkUniqueness($data, $product->id);
            if ($error) return ['success' => false, 'message' => $error];

            $product->update([
                'name'                  => $data['name'],
                'slug'                  => sanitize_title($data['name']),
                'description'           => $data['description'] ?? null,
                'status'                => $data['status'],
                'provider_id'  => !empty($data['product_id']) ? (string) $data['product_id'] : null,
                'type'                  => $data['option_type'] ?? 'single',
                'provider_product_name' => $data['provider_product_name'] ?? null,
                'product_link'          => $data['product_link'] ?? null,
            ]);

            // Sync variations
            $this->syncOptions($options, $product);

            return ['success' => true, 'message' => __('Product updated successfully', 'licenzo'), 'product' => $product];
        } catch (\Throwable $th) {
            return ['success' => false, 'message' => (defined('WP_DEBUG') && WP_DEBUG) ? 'Error updating product: ' . $th->getMessage() : __('An error occurred', 'licenzo')];
        }
    }

    /**
     * Delete a product
     */
    public function destroy($id)
    {
        try {
            $product = Product::find($id);
            if (!$product) return ['success' => false, 'message' => __('Product not found.', 'licenzo')];

            $product->variations()->delete();
            $product->delete();

            return ['success' => true, 'message' => __('Product deleted successfully.', 'licenzo')];
        } catch (\Throwable $th) {
            return ['success' => false, 'message' => (defined('WP_DEBUG') && WP_DEBUG) ? 'Error deleting product: ' . $th->getMessage() : __('An error occurred', 'licenzo')];
        }
    }

    /**
     * Helper to sync variations
     */
    private function syncOptions($options, Product $product)
    {

        if (!is_array($options)) return;

        $optionIds = array_filter(array_column($options, 'id'));
        $product->variations()
            ->whereNotIn('id', $optionIds ?: [0])
            ->delete()
        ;

        foreach ($options as $option) {
            $data = [
                'name'                  => !empty($option['name']) ? $option['name'] : $product->name,
                'provider_id' => !empty($option['variation_id']) ? (string) $option['variation_id'] : null,
                'currency'              => $option['currency'] ?? (function_exists('get_woocommerce_currency') ? get_woocommerce_currency() : 'USD'),
                'billing_cycle'           => $option['cycle'] ?? 'monthly',
                'regular_price'         => floatval($option['regular_price'] ?? 0.00),
                'sale_price'            => floatval($option['sale_price'] ?? 0.00),
                'max_activations'       => intval($option['max_activation'] ?? 1),
                'support_for_unit'      => $option['support_for_unit'] ?? 'day',
                'support_for'           => intval($option['support_for'] ?? 0),
                'trial_days'            => intval($option['trial_days'] ?? null),
            ];

            if (!empty($option['id']) && $existing = ProductVariation::find($option['id'])) {
                $existing->update($data);
            } else {
                ProductVariation::create(array_merge($data, [
                    'uuid'       => wp_generate_uuid4(),
                    'product_id' => $product->id,
                ]));
            }
        }
        return $product->variations;
    }


    /**
     * Sanitize option/variation arrays from request input
     */
    private function sanitizeOptions(array $options): array
    {
        return array_map(function ($option) {
            return [
                'id'               => isset($option['id']) ? absint($option['id']) : null,
                'name'             => isset($option['name']) ? sanitize_text_field($option['name']) : '',
                'variation_id'     => isset($option['variation_id']) ? intval($option['variation_id']) : null,
                'cycle'            => isset($option['cycle']) ? sanitize_text_field($option['cycle']) : 'monthly',
                'regular_price'    => isset($option['regular_price']) ? floatval($option['regular_price']) : 0.00,
                'sale_price'       => isset($option['sale_price']) ? floatval($option['sale_price']) : 0.00,
                'max_activation'   => isset($option['max_activation']) ? intval($option['max_activation']) : 1,
                'support_for_unit' => isset($option['support_for_unit']) ? sanitize_text_field($option['support_for_unit']) : 'day',
                'support_for'      => isset($option['support_for']) ? intval($option['support_for']) : 0,
                'trial_days'       => isset($option['trial_days']) ? intval($option['trial_days']) : 0,
            ];
        }, $options);
    }

    /**
     * Validate pricing option mappings for duplicate cycles and duplicate identities.
     */
    private function validateOptionMappings(array $options, array $data, ?Product $existingProduct = null): ?string
    {
        if (empty($options)) {
            return __('At least one pricing option is required.', 'licenzo');
        }

        $optionType = strtolower((string) ($data['option_type'] ?? ($existingProduct ? $existingProduct->type : 'single')));
        $sourceType = strtolower((string) ($data['source_type'] ?? (($existingProduct && ProviderAliasService::isWoo((string) $existingProduct->provider)) ? 'provider' : 'manual')));

        if ($optionType === 'single' && count($options) > 1) {
            return __('Single product can only have one pricing mapping.', 'licenzo');
        }

        $seenCycles = [];
        $seenProviderVariationIds = [];
        $seenManualVariationNames = [];

        foreach ($options as $option) {
            $normalizedCycle = strtolower(trim((string) ($option['cycle'] ?? 'monthly')));
            $normalizedCycle = $normalizedCycle === '' ? 'monthly' : $normalizedCycle;

            if (isset($seenCycles[$normalizedCycle])) {
                return __('This billing cycle is already mapped for this product.', 'licenzo');
            }
            $seenCycles[$normalizedCycle] = true;

            if ($sourceType === 'provider' && $optionType === 'variation') {
                $variationId = absint($option['variation_id'] ?? 0);
                if ($variationId <= 0) {
                    return __('Please select a variation.', 'licenzo');
                }

                if (isset($seenProviderVariationIds[$variationId])) {
                    return __('This WooCommerce variation is already mapped.', 'licenzo');
                }
                $seenProviderVariationIds[$variationId] = true;
            }

            if ($sourceType === 'manual' && $optionType === 'variation') {
                $variationName = strtolower(trim(preg_replace('/\s+/', ' ', (string) ($option['name'] ?? ''))));
                if ($variationName === '') {
                    return __('Variation name is required.', 'licenzo');
                }

                if (isset($seenManualVariationNames[$variationName])) {
                    return __('This variation is already mapped.', 'licenzo');
                }
                $seenManualVariationNames[$variationName] = true;
            }
        }

        return null;
    }


    /**
     * Check Uniqueness
     */
    private function checkUniqueness(array $data, ?int $ignoreId = null)
    {
        $nameQuery = Product::where('name', $data['name']);
        if ($ignoreId) {
            $nameQuery->where('id', '!=', $ignoreId);
        }
        if ($nameQuery->exists()) {
            return __('Product name already exists.', 'licenzo');
        }
        if (!empty($data['product_id']) && ($data['source_type'] ?? '') === 'provider') {
            $providerQuery = Product::whereIn('provider', ProviderAliasService::wooAliases())
                ->where('provider_id', (string) $data['product_id']);
            if ($ignoreId) {
                $providerQuery->where('id', '!=', $ignoreId);
            }
            if ($providerQuery->exists()) {
                return __('This provider product already exists.', 'licenzo');
            }
        }

        return null;
    }

    /**
     * Get all products with variations
     */
    public function allProducts(Request $request)
    {
        try {

            $search = $request->getSafe('search', 'sanitize_text_field', '');

            $query = Product::query()->orderBy('created_at', 'desc');

            if (!empty($search)) {
                global $wpdb;
                $searchTerm = '%' . $wpdb->esc_like($search) . '%';
                $query->where(function ($q) use ($searchTerm) {
                    $q->where('name', 'LIKE', $searchTerm)
                        ->orWhere('description', 'LIKE', $searchTerm)
                    ;
                });
            }

            $products = $query->with('variations')->limit(20)->get();

            return [
                'success'  => true,
                'products' => $products,
            ];
        } catch (\Throwable $th) {
            return [
                'success' => false,
                'message' => (defined('WP_DEBUG') && WP_DEBUG) ? 'Error fetching all products: ' . $th->getMessage() : __('An error occurred', 'licenzo'),
            ];
        }
    }
}
