<?php

namespace App\Http\Controllers\Owner;

use App\Http\Controllers\Controller;
use App\Models\ArtistItem;
use App\Models\CatalogPriceRule;
use App\Models\GiftItem;
use App\Models\OtherCostItem;
use App\Models\SerenataPackage;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;

class CatalogPriceRuleController extends Controller
{
    private function targetMap(): array
    {
        return [
            'gift' => GiftItem::class,
            'artist' => ArtistItem::class,
            'other_cost' => OtherCostItem::class,
            'package' => SerenataPackage::class,
        ];
    }

    private function resolveTarget(Request $request, string $targetType, int $targetId): ?Model
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        if ($organizationId <= 0) {
            return null;
        }

        $targetClass = $this->targetMap()[$targetType] ?? null;
        if (!$targetClass) {
            return null;
        }

        return $targetClass::query()
            ->where('organization_id', $organizationId)
            ->whereKey($targetId)
            ->first();
    }

    private function validatedData(Request $request, string $targetType): array
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:120'],
            'rule_type' => ['required', 'in:always,weekday,date_range,specific_date'],
            'weekday_values' => ['nullable', 'array'],
            'weekday_values.*' => ['integer', 'min:1', 'max:7'],
            'start_date' => ['nullable', 'date'],
            'end_date' => ['nullable', 'date'],
            'specific_date' => ['nullable', 'date'],
            'customer_price' => ['nullable', 'numeric', 'min:0'],
            'internal_cost' => ['nullable', 'numeric', 'min:0'],
            'apply_package_items_override' => ['nullable', 'boolean'],
            'gift_codes' => ['nullable', 'array'],
            'gift_codes.*' => ['string', 'max:120'],
            'artist_codes' => ['nullable', 'array'],
            'artist_codes.*' => ['string', 'max:120'],
            'other_cost_codes' => ['nullable', 'array'],
            'other_cost_codes.*' => ['string', 'max:120'],
            'priority' => ['nullable', 'integer', 'min:1', 'max:9999'],
            'is_active' => ['required', 'boolean'],
        ]);

        $ruleType = (string) $data['rule_type'];

        if ($ruleType === CatalogPriceRule::TYPE_WEEKDAY) {
            $weekdays = array_values(array_unique(array_map('intval', $data['weekday_values'] ?? [])));
            if (empty($weekdays)) {
                throw ValidationException::withMessages([
                    'weekday_values' => 'Selecciona al menos un día de la semana.',
                ]);
            }
            sort($weekdays);
            $data['weekday_values'] = $weekdays;
            $data['start_date'] = null;
            $data['end_date'] = null;
            $data['specific_date'] = null;
        } elseif ($ruleType === CatalogPriceRule::TYPE_DATE_RANGE) {
            $start = $data['start_date'] ?? null;
            $end = $data['end_date'] ?? null;
            if (!$start || !$end) {
                throw ValidationException::withMessages([
                    'start_date' => 'Debes seleccionar fecha inicial y final.',
                    'end_date' => 'Debes seleccionar fecha inicial y final.',
                ]);
            }
            if (Carbon::parse($start)->gt(Carbon::parse($end))) {
                throw ValidationException::withMessages([
                    'start_date' => 'La fecha inicial no puede ser mayor que la final.',
                ]);
            }
            $data['weekday_values'] = null;
            $data['specific_date'] = null;
        } elseif ($ruleType === CatalogPriceRule::TYPE_SPECIFIC_DATE) {
            if (empty($data['specific_date'])) {
                throw ValidationException::withMessages([
                    'specific_date' => 'Selecciona una fecha puntual.',
                ]);
            }
            $data['weekday_values'] = null;
            $data['start_date'] = null;
            $data['end_date'] = null;
        } else {
            $data['weekday_values'] = null;
            $data['start_date'] = null;
            $data['end_date'] = null;
            $data['specific_date'] = null;
        }

        $giftCodesInput = array_values(array_unique(array_filter(array_map('strval', $data['gift_codes'] ?? []))));
        $artistCodesInput = array_values(array_unique(array_filter(array_map('strval', $data['artist_codes'] ?? []))));
        $otherCostCodesInput = array_values(array_unique(array_filter(array_map('strval', $data['other_cost_codes'] ?? []))));
        $hasAnyCompositionSelection = !empty($giftCodesInput) || !empty($artistCodesInput) || !empty($otherCostCodesInput);

        $applyItemsOverride = $targetType === 'package'
            && (!empty($data['apply_package_items_override']) || $hasAnyCompositionSelection);
        if ($applyItemsOverride) {
            $data['gift_codes'] = $giftCodesInput;
            $data['artist_codes'] = $artistCodesInput;
            $data['other_cost_codes'] = $otherCostCodesInput;
        } else {
            $data['gift_codes'] = null;
            $data['artist_codes'] = null;
            $data['other_cost_codes'] = null;
        }

        if (($data['customer_price'] ?? null) === null
            && ($data['internal_cost'] ?? null) === null
            && !$applyItemsOverride) {
            throw ValidationException::withMessages([
                'customer_price' => 'Define precio/costo o activa composición especial del paquete.',
            ]);
        }

        return $data;
    }

    public function index(Request $request): JsonResponse
    {
        $targetType = (string) $request->query('target_type', '');
        $targetId = (int) $request->query('target_id', 0);

        $target = $this->resolveTarget($request, $targetType, $targetId);
        if (!$target) {
            return response()->json(['success' => false, 'message' => 'Ítem no encontrado.'], 404);
        }

        $rules = $target->priceRules()
            ->orderBy('priority')
            ->orderByDesc('id')
            ->get()
            ->map(fn (CatalogPriceRule $rule) => [
                'id' => (int) $rule->id,
                'name' => (string) $rule->name,
                'rule_type' => (string) $rule->rule_type,
                'weekday_values' => array_values($rule->weekday_values ?? []),
                'start_date' => optional($rule->start_date)->format('Y-m-d'),
                'end_date' => optional($rule->end_date)->format('Y-m-d'),
                'specific_date' => optional($rule->specific_date)->format('Y-m-d'),
                'customer_price' => $rule->customer_price,
                'internal_cost' => $rule->internal_cost,
                'gift_codes' => array_values($rule->gift_codes ?? []),
                'artist_codes' => array_values($rule->artist_codes ?? []),
                'other_cost_codes' => array_values($rule->other_cost_codes ?? []),
                'has_item_overrides' => !is_null($rule->gift_codes) || !is_null($rule->artist_codes) || !is_null($rule->other_cost_codes),
                'priority' => (int) $rule->priority,
                'is_active' => (bool) $rule->is_active,
            ]);

        return response()->json(['success' => true, 'rules' => $rules]);
    }

    public function store(Request $request): JsonResponse
    {
        $targetType = (string) $request->input('target_type', '');
        $targetId = (int) $request->input('target_id', 0);

        $target = $this->resolveTarget($request, $targetType, $targetId);
        if (!$target) {
            return response()->json(['success' => false, 'message' => 'Ítem no encontrado.'], 404);
        }

        $data = $this->validatedData($request, $targetType);

        $rule = $target->priceRules()->create([
            'organization_id' => (int) ($request->user()->organization_id ?? 0),
            ...$data,
            'priority' => (int) ($data['priority'] ?? 100),
            'is_active' => (bool) $data['is_active'],
        ]);

        return response()->json([
            'success' => true,
            'message' => 'Regla de precio creada.',
            'rule_id' => (int) $rule->id,
        ]);
    }

    public function update(Request $request, CatalogPriceRule $catalogPriceRule): JsonResponse
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        if ($organizationId <= 0 || $catalogPriceRule->organization_id !== $organizationId) {
            return response()->json(['success' => false, 'message' => 'Regla no encontrada.'], 404);
        }

        $targetType = match ($catalogPriceRule->priceable_type) {
            GiftItem::class => 'gift',
            ArtistItem::class => 'artist',
            OtherCostItem::class => 'other_cost',
            SerenataPackage::class => 'package',
            default => '',
        };
        $data = $this->validatedData($request, $targetType);

        $catalogPriceRule->update([
            ...$data,
            'priority' => (int) ($data['priority'] ?? 100),
            'is_active' => (bool) $data['is_active'],
        ]);

        return response()->json([
            'success' => true,
            'message' => 'Regla de precio actualizada.',
        ]);
    }

    public function destroy(Request $request, CatalogPriceRule $catalogPriceRule): JsonResponse
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        if ($organizationId <= 0 || $catalogPriceRule->organization_id !== $organizationId) {
            return response()->json(['success' => false, 'message' => 'Regla no encontrada.'], 404);
        }

        $catalogPriceRule->delete();

        return response()->json([
            'success' => true,
            'message' => 'Regla eliminada.',
        ]);
    }
}
