<?php

namespace App\Http\Controllers\Owner;

use App\Http\Controllers\Controller;
use App\Models\QuoteTransportRule;
use App\Models\SerenataPackage;
use App\Support\Pricing\CatalogPriceResolver;
use Illuminate\Http\Request;

class QuoteCalculatorController extends Controller
{
    private function normalize(string $value): string
    {
        return mb_strtolower(trim($value), 'UTF-8');
    }

    private function rulesForOrg(int $organizationId)
    {
        return QuoteTransportRule::query()
            ->where('organization_id', $organizationId)
            ->where('is_active', true)
            ->orderBy('sort_order')
            ->orderBy('name')
            ->get();
    }

    private function matchScore(QuoteTransportRule $rule, string $city, string $zone): array
    {
        $ruleCity = $this->normalize((string) $rule->city);
        $cityNorm = $this->normalize($city);
        $zoneNorm = $this->normalize($zone);

        $cityMatch = $ruleCity === '*' || $ruleCity === $cityNorm;
        if (!$cityMatch) {
            return [false, 0, 0];
        }

        $keywords = collect(explode(',', (string) $rule->zone_keywords))
            ->map(fn ($k) => trim($k))
            ->filter()
            ->values();

        $zoneHits = 0;
        foreach ($keywords as $keyword) {
            if (str_contains($zoneNorm, $this->normalize($keyword))) {
                $zoneHits++;
            }
        }

        $citySpecificity = $ruleCity === '*' ? 0 : 1;

        return [true, $zoneHits, $citySpecificity];
    }

    private function resolveRule($rules, string $city, string $zone): ?QuoteTransportRule
    {
        $scored = $rules->map(function (QuoteTransportRule $rule) use ($city, $zone) {
            [$ok, $zoneHits, $citySpecificity] = $this->matchScore($rule, $city, $zone);
            return [
                'ok' => $ok,
                'zone_hits' => $zoneHits,
                'city_specificity' => $citySpecificity,
                'sort_order' => (int) $rule->sort_order,
                'rule' => $rule,
            ];
        })->filter(fn ($row) => $row['ok']);

        if ($scored->isEmpty()) {
            return null;
        }

        return $scored
            ->sortByDesc('zone_hits')
            ->sortByDesc('city_specificity')
            ->sortBy('sort_order')
            ->pluck('rule')
            ->first();
    }

    private function calculateTransport(QuoteTransportRule $rule, float $distanceKm): array
    {
        if ($rule->pricing_mode === QuoteTransportRule::MODE_FIXED) {
            $amount = max(0, (float) $rule->fixed_amount);
            return [
                'amount' => $amount,
                'formula' => 'Tarifa fija',
            ];
        }

        $base = max(0, (float) $rule->fixed_amount);
        $baseKm = max(0, (float) $rule->base_km);
        $perKm = max(0, (float) $rule->per_km_amount);
        $min = max(0, (float) $rule->min_amount);
        $extraKm = max(0, $distanceKm - $baseKm);
        $amount = $base + ($extraKm * $perKm);
        $amount = max($amount, $min);

        return [
            'amount' => $amount,
            'formula' => "Base {$base} + ({$extraKm} km x {$perKm}), mínimo {$min}",
        ];
    }

    public function index(Request $request)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        abort_if($organizationId <= 0, 403);

        $rules = $this->rulesForOrg($organizationId);
        $packages = SerenataPackage::query()
            ->where('organization_id', $organizationId)
            ->where('is_active', true)
            ->orderByDesc('is_default')
            ->orderBy('sort_order')
            ->orderBy('name')
            ->get();
        $cities = $rules->pluck('city')
            ->map(fn ($city) => trim((string) $city))
            ->filter(fn ($city) => $city !== '*')
            ->unique(fn ($city) => $this->normalize($city))
            ->values()
            ->all();
        $packages->each(function (SerenataPackage $package) {
            $resolved = CatalogPriceResolver::resolve($package);
            $package->base_price = (float) $resolved['customer_price'];
        });

        return view('content.owner.quotes.calculator', [
            'rules' => $rules,
            'packages' => $packages,
            'cities' => $cities,
            'result' => null,
        ]);
    }

    public function calculate(Request $request)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        abort_if($organizationId <= 0, 403);

        $rules = $this->rulesForOrg($organizationId);
        $packages = SerenataPackage::query()
            ->where('organization_id', $organizationId)
            ->where('is_active', true)
            ->orderByDesc('is_default')
            ->orderBy('sort_order')
            ->orderBy('name')
            ->get();
        $cities = $rules->pluck('city')
            ->map(fn ($city) => trim((string) $city))
            ->filter(fn ($city) => $city !== '*')
            ->unique(fn ($city) => $this->normalize($city))
            ->values()
            ->all();

        $data = $request->validate([
            'city' => ['required', 'string', 'max:120'],
            'zone' => ['nullable', 'string', 'max:255'],
            'distance_km' => ['nullable', 'numeric', 'min:0'],
            'base_service' => ['required', 'numeric', 'min:0'],
            'extras' => ['nullable', 'numeric', 'min:0'],
            'discount' => ['nullable', 'numeric', 'min:0'],
            'quote_date' => ['nullable', 'date'],
            'package_id' => ['nullable', 'integer', 'min:1'],
            'transport_rule_id' => ['nullable', 'integer', 'min:1'],
        ]);

        $city = trim((string) $data['city']);
        $zone = trim((string) ($data['zone'] ?? ''));
        $distanceKm = (float) ($data['distance_km'] ?? 0);
        $baseService = (float) ($data['base_service'] ?? 0);
        $extras = (float) ($data['extras'] ?? 0);
        $discount = (float) ($data['discount'] ?? 0);
        $quoteDate = !empty($data['quote_date']) ? (string) $data['quote_date'] : null;
        $packages->each(function (SerenataPackage $package) use ($quoteDate) {
            $resolved = CatalogPriceResolver::resolve($package, $quoteDate);
            $package->base_price = (float) $resolved['customer_price'];
        });
        $selectedPackage = null;
        if (!empty($data['package_id'])) {
            $selectedPackage = $packages->firstWhere('id', (int) $data['package_id']);
            if ($selectedPackage && $baseService <= 0) {
                $resolvedPackage = CatalogPriceResolver::resolve($selectedPackage, $quoteDate);
                $baseService = (float) $resolvedPackage['customer_price'];
                $selectedPackage->base_price = (float) $resolvedPackage['customer_price'];
            }
        }

        $selectedRule = null;
        if (!empty($data['transport_rule_id'])) {
            $selectedRule = $rules->firstWhere('id', (int) $data['transport_rule_id']);
        }
        if (!$selectedRule) {
            $selectedRule = $this->resolveRule($rules, $city, $zone);
        }

        $transport = [
            'amount' => 0,
            'formula' => 'Sin regla aplicada',
        ];
        if ($selectedRule) {
            $transport = $this->calculateTransport($selectedRule, $distanceKm);
        }

        $subtotal = max(0, $baseService + $extras + (float) $transport['amount']);
        $total = max(0, $subtotal - $discount);

        $result = [
            'city' => $city,
            'zone' => $zone,
            'distance_km' => $distanceKm,
            'base_service' => $baseService,
            'extras' => $extras,
            'discount' => $discount,
            'transport_amount' => (float) $transport['amount'],
            'transport_formula' => $transport['formula'],
            'subtotal' => $subtotal,
            'total' => $total,
            'rule' => $selectedRule,
            'package' => $selectedPackage,
        ];

        return view('content.owner.quotes.calculator', [
            'rules' => $rules,
            'packages' => $packages,
            'cities' => $cities,
            'result' => $result,
        ]);
    }
}
