<?php

declare(strict_types=1);

namespace Instinctor\Services;

use Instinctor\Core\Config;
use Instinctor\Core\DB;


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

/**
 * Variation Service
 * Manages product variations (size, color, etc.)
 */
class VariationService
{
    public function getVariations(int $productId): array
    {
        $table = DB::prefix() . 'instinctor_product_variations';
        
        $variations = DB::get_results(DB::prepare(
            "SELECT * FROM $table WHERE product_id = %d AND enabled = 1 ORDER BY sort_order, id",
            $productId
        ));

        foreach ($variations as &$v) {
            $v->attributes = json_decode($v->attributes, true) ?: [];
        }

        return $variations;
    }

    public function getAllVariations(int $productId): array
    {
        $table = DB::prefix() . 'instinctor_product_variations';
        
        $variations = DB::get_results(DB::prepare(
            "SELECT * FROM $table WHERE product_id = %d ORDER BY sort_order, id",
            $productId
        ));

        foreach ($variations as &$v) {
            $v->attributes = json_decode($v->attributes, true) ?: [];
        }

        return $variations;
    }

    public function getVariation(int $id): ?object
    {
        $table = DB::prefix() . 'instinctor_product_variations';
        
        $variation = DB::get_row(DB::prepare("SELECT * FROM $table WHERE id = %d", $id));
        
        if ($variation) {
            $variation->attributes = json_decode($variation->attributes, true) ?: [];
        }

        return $variation;
    }

    public function getVariationByAttributes(int $productId, array $attributes): ?object
    {
        $variations = $this->getVariations($productId);
        
        foreach ($variations as $variation) {
            if ($this->attributesMatch($variation->attributes, $attributes)) {
                return $variation;
            }
        }

        return null;
    }

    private function attributesMatch(array $variationAttrs, array $selectedAttrs): bool
    {
        foreach ($selectedAttrs as $key => $value) {
            if (!isset($variationAttrs[$key]) || strtolower($variationAttrs[$key]) !== strtolower($value)) {
                return false;
            }
        }
        return true;
    }

    public function createVariation(array $data): int
    {
        $table = DB::prefix() . 'instinctor_product_variations';

        DB::insert($table, [
            'product_id' => intval($data['product_id']),
            'sku' => sanitize_text_field($data['sku'] ?? ''),
            'price' => isset($data['price']) ? floatval($data['price']) : null,
            'sale_price' => !empty($data['sale_price']) ? floatval($data['sale_price']) : null,
            'stock_quantity' => isset($data['stock_quantity']) ? intval($data['stock_quantity']) : null,
            'stock_status' => sanitize_text_field($data['stock_status'] ?? 'instock'),
            'attributes' => json_encode($data['attributes'] ?? []),
            'image' => !empty($data['image']) ? intval($data['image']) : null,
            'enabled' => isset($data['enabled']) ? ($data['enabled'] ? 1 : 0) : 1,
            'sort_order' => intval($data['sort_order'] ?? 0),
        ]);

        return (int) DB::insert_id();
    }

    public function updateVariation(int $id, array $data): bool
    {
        $table = DB::prefix() . 'instinctor_product_variations';

        $update = [];
        if (isset($data['sku'])) $update['sku'] = sanitize_text_field($data['sku']);
        if (array_key_exists('price', $data)) $update['price'] = $data['price'] !== null ? floatval($data['price']) : null;
        if (array_key_exists('sale_price', $data)) $update['sale_price'] = !empty($data['sale_price']) ? floatval($data['sale_price']) : null;
        if (array_key_exists('stock_quantity', $data)) $update['stock_quantity'] = $data['stock_quantity'] !== null ? intval($data['stock_quantity']) : null;
        if (isset($data['stock_status'])) $update['stock_status'] = sanitize_text_field($data['stock_status']);
        if (isset($data['attributes'])) $update['attributes'] = json_encode($data['attributes']);
        if (array_key_exists('image', $data)) $update['image'] = !empty($data['image']) ? intval($data['image']) : null;
        if (isset($data['enabled'])) $update['enabled'] = $data['enabled'] ? 1 : 0;
        if (isset($data['sort_order'])) $update['sort_order'] = intval($data['sort_order']);

        return DB::update($table, $update, ['id' => $id]) !== false;
    }

    public function deleteVariation(int $id): bool
    {
        return DB::delete(DB::prefix() . 'instinctor_product_variations', ['id' => $id]) !== false;
    }

    public function deleteProductVariations(int $productId): bool
    {
        return DB::delete(DB::prefix() . 'instinctor_product_variations', ['product_id' => $productId]) !== false;
    }

    /**
     * Get unique attribute values for a product
     */
    public function getProductAttributes(int $productId): array
    {
        $variations = $this->getVariations($productId);
        $attributes = [];

        foreach ($variations as $v) {
            foreach ($v->attributes as $key => $value) {
                if (!isset($attributes[$key])) {
                    $attributes[$key] = [];
                }
                if (!in_array($value, $attributes[$key])) {
                    $attributes[$key][] = $value;
                }
            }
        }

        return $attributes;
    }

    /**
     * Check if product has variations
     */
    public function hasVariations(int $productId): bool
    {
        $table = DB::prefix() . 'instinctor_product_variations';
        
        $count = DB::get_var(DB::prepare(
            "SELECT COUNT(*) FROM $table WHERE product_id = %d AND enabled = 1",
            $productId
        ));

        return $count > 0;
    }

    /**
     * Get price range for variable product
     */
    public function getPriceRange(int $productId): array
    {
        $table = DB::prefix() . 'instinctor_product_variations';
        
        $result = DB::get_row(DB::prepare(
            "SELECT 
                MIN(COALESCE(sale_price, price)) as min_price,
                MAX(COALESCE(sale_price, price)) as max_price
             FROM $table 
             WHERE product_id = %d AND enabled = 1 AND price IS NOT NULL",
            $productId
        ));

        return [
            'min' => $result ? (float) $result->min_price : 0,
            'max' => $result ? (float) $result->max_price : 0,
        ];
    }

    /**
     * Bulk create variations from attribute combinations
     */
    public function generateVariations(int $productId, array $attributes, float $basePrice): int
    {
        // Generate all combinations
        $combinations = $this->generateCombinations($attributes);
        $created = 0;

        foreach ($combinations as $combo) {
            $this->createVariation([
                'product_id' => $productId,
                'price' => $basePrice,
                'attributes' => $combo,
                'enabled' => true,
            ]);
            $created++;
        }

        return $created;
    }

    private function generateCombinations(array $attributes, int $index = 0, array $current = []): array
    {
        $keys = array_keys($attributes);
        
        if ($index >= count($keys)) {
            return [$current];
        }

        $key = $keys[$index];
        $values = $attributes[$key];
        $combinations = [];

        foreach ($values as $value) {
            $newCurrent = $current;
            $newCurrent[$key] = $value;
            $combinations = array_merge(
                $combinations, 
                $this->generateCombinations($attributes, $index + 1, $newCurrent)
            );
        }

        return $combinations;
    }
}
