<?php

namespace App\Http\Controllers\Owner;

use App\Http\Controllers\Controller;
use App\Models\ArtistItem;
use App\Models\GiftItem;
use App\Models\MariachiGroup;
use App\Models\OtherCostItem;
use App\Models\SerenataPackage;
use App\Support\OwnerWorkspace;
use Illuminate\Http\Request;

class SerenataPackageController extends Controller
{
    private function redirectAfterPackageMutation(Request $request, int $groupId, string $message)
    {
        $returnToGroupId = (int) ($request->input('return_to_group_id', $request->query('return_to_group_id', 0)) ?? 0);
        if ($returnToGroupId > 0) {
            return redirect()
                ->to(route('owner.settings.mariachi-groups.show', $returnToGroupId) . '#group-packages')
                ->with('status', $message);
        }

        return redirect()->route('owner.settings.packages', [
            'mariachi_group_id' => $groupId,
        ])->with('status', $message);
    }

    private function resolveGroup(Request $request, int $organizationId): ?MariachiGroup
    {
        if ($organizationId <= 0) {
            return null;
        }

        $query = MariachiGroup::query()
            ->where('organization_id', $organizationId);

        $requestedGroupId = (int) ($request->query('mariachi_group_id', $request->input('mariachi_group_id', 0)) ?? 0);

        if ($requestedGroupId > 0) {
            return $query->whereKey($requestedGroupId)->first();
        }

        return $query
            ->orderByDesc('is_default')
            ->orderBy('sort_order')
            ->orderBy('name')
            ->first();
    }

    private function uniqueCodes(array $codes): array
    {
        return array_values(array_unique(array_filter(array_map('strval', $codes))));
    }

    private function calculatePackageInternalCost(int $organizationId, int $mariachiGroupId, array $giftCodes, array $artistCodes, array $otherCostCodes): float
    {
        $giftCosts = GiftItem::query()
            ->where('organization_id', $organizationId)
            ->where('mariachi_group_id', $mariachiGroupId)
            ->whereIn('code', $giftCodes)
            ->pluck('internal_cost', 'code');

        $artistCosts = ArtistItem::query()
            ->where('organization_id', $organizationId)
            ->where('mariachi_group_id', $mariachiGroupId)
            ->whereIn('code', $artistCodes)
            ->pluck('internal_cost', 'code');

        $otherCosts = OtherCostItem::query()
            ->where('organization_id', $organizationId)
            ->where('mariachi_group_id', $mariachiGroupId)
            ->whereIn('code', $otherCostCodes)
            ->pluck('internal_cost', 'code');

        $giftSum = collect($giftCodes)->sum(fn (string $code) => (float) ($giftCosts[$code] ?? 0));
        $artistSum = collect($artistCodes)->sum(fn (string $code) => (float) ($artistCosts[$code] ?? 0));
        $otherSum = collect($otherCostCodes)->sum(fn (string $code) => (float) ($otherCosts[$code] ?? 0));

        return (float) round(max(0, $giftSum + $artistSum + $otherSum), 2);
    }

    private function catalogs(int $organizationId, int $mariachiGroupId): array
    {
        return [
            'giftOptions' => GiftItem::query()
                ->where('organization_id', $organizationId)
                ->where('mariachi_group_id', $mariachiGroupId)
                ->where('is_active', true)
                ->orderBy('type')
                ->orderBy('sort_order')
                ->orderBy('name')
                ->get(['code', 'name', 'base_price', 'internal_cost', 'type']),
            'artistOptions' => ArtistItem::query()
                ->where('organization_id', $organizationId)
                ->where('mariachi_group_id', $mariachiGroupId)
                ->where('is_active', true)
                ->orderBy('type')
                ->orderBy('sort_order')
                ->orderBy('name')
                ->get(['code', 'name', 'base_price', 'internal_cost', 'type']),
            'otherCostOptions' => OtherCostItem::query()
                ->where('organization_id', $organizationId)
                ->where('mariachi_group_id', $mariachiGroupId)
                ->where('is_active', true)
                ->orderBy('sort_order')
                ->orderBy('name')
                ->get(['code', 'name', 'base_price', 'internal_cost']),
        ];
    }

    public function index(Request $request)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        $canManage = $organizationId > 0;
        $groups = $canManage ? OwnerWorkspace::groupsForOrganization($organizationId) : collect();
        $currentGroup = $canManage ? $this->resolveGroup($request, $organizationId) : null;

        if ($currentGroup) {
            $currentGroup->ensureOwnCatalog();
        }

        $items = ($canManage && $currentGroup)
            ? SerenataPackage::query()
                ->where('organization_id', $organizationId)
                ->where('mariachi_group_id', (int) $currentGroup->id)
                ->orderBy('sort_order')
                ->orderBy('name')
                ->get()
            : collect();

        $catalogs = ($canManage && $currentGroup) ? $this->catalogs($organizationId, (int) $currentGroup->id) : [
            'giftOptions' => collect(),
            'artistOptions' => collect(),
            'otherCostOptions' => collect(),
        ];

        return view('content.owner.settings.packages.index', [
            'canManagePackages' => $canManage,
            'currentGroup' => $currentGroup,
            'mariachiGroups' => $groups,
            'items' => $items,
            ...$catalogs,
        ]);
    }

    public function store(Request $request)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        $currentGroup = $this->resolveGroup($request, $organizationId);
        if ($organizationId <= 0 || !$currentGroup) {
            return back()->withErrors(['name' => 'Primero debes tener una organización asignada.']);
        }

        $data = $request->validate([
            'name' => ['required', 'string', 'max:120'],
            'city' => ['required', 'string', 'max:120'],
            'commission_amount' => ['required', 'numeric', 'min:0'],
            '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'],
            'is_active' => ['required', 'boolean'],
            'is_default' => ['required', 'boolean'],
            'sort_order' => ['nullable', 'integer', 'min:0', 'max:9999'],
        ]);

        if (!empty($data['is_default'])) {
            SerenataPackage::query()
                ->where('organization_id', $organizationId)
                ->where('mariachi_group_id', (int) $currentGroup->id)
                ->update(['is_default' => false]);
        }

        $giftCodes = $this->uniqueCodes($data['gift_codes'] ?? []);
        $artistCodes = $this->uniqueCodes($data['artist_codes'] ?? []);
        $otherCostCodes = $this->uniqueCodes($data['other_cost_codes'] ?? []);
        $internalCost = $this->calculatePackageInternalCost($organizationId, (int) $currentGroup->id, $giftCodes, $artistCodes, $otherCostCodes);
        $commissionAmount = (float) $data['commission_amount'];
        $basePrice = (float) round(max(0, $internalCost + $commissionAmount), 2);

        SerenataPackage::create([
            'organization_id' => $organizationId,
            'mariachi_group_id' => (int) $currentGroup->id,
            'name' => trim((string) $data['name']),
            'city' => trim((string) ($data['city'] ?: '*')),
            'internal_cost' => $internalCost,
            'commission_amount' => $commissionAmount,
            'base_price' => $basePrice,
            'gift_codes' => $giftCodes,
            'artist_codes' => $artistCodes,
            'other_cost_codes' => $otherCostCodes,
            'is_active' => (bool) $data['is_active'],
            'is_default' => (bool) $data['is_default'],
            'sort_order' => (int) ($data['sort_order'] ?? 100),
        ]);

        return $this->redirectAfterPackageMutation($request, (int) $currentGroup->id, 'Paquete creado correctamente.');
    }

    public function update(Request $request, SerenataPackage $serenataPackage)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        if (
            $organizationId <= 0
            || $serenataPackage->organization_id !== $organizationId
            || !OwnerWorkspace::canAccessGroup($request->user(), (int) $serenataPackage->mariachi_group_id)
        ) {
            abort(404);
        }

        $data = $request->validate([
            'name' => ['required', 'string', 'max:120'],
            'city' => ['required', 'string', 'max:120'],
            'commission_amount' => ['required', 'numeric', 'min:0'],
            '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'],
            'is_active' => ['required', 'boolean'],
            'is_default' => ['required', 'boolean'],
            'sort_order' => ['nullable', 'integer', 'min:0', 'max:9999'],
        ]);

        if (!empty($data['is_default'])) {
            SerenataPackage::query()
                ->where('organization_id', $organizationId)
                ->where('mariachi_group_id', (int) $serenataPackage->mariachi_group_id)
                ->where('id', '!=', $serenataPackage->id)
                ->update(['is_default' => false]);
        }

        $giftCodes = $this->uniqueCodes($data['gift_codes'] ?? []);
        $artistCodes = $this->uniqueCodes($data['artist_codes'] ?? []);
        $otherCostCodes = $this->uniqueCodes($data['other_cost_codes'] ?? []);
        $internalCost = $this->calculatePackageInternalCost($organizationId, (int) $serenataPackage->mariachi_group_id, $giftCodes, $artistCodes, $otherCostCodes);
        $commissionAmount = (float) $data['commission_amount'];
        $basePrice = (float) round(max(0, $internalCost + $commissionAmount), 2);

        $serenataPackage->update([
            'name' => trim((string) $data['name']),
            'city' => trim((string) ($data['city'] ?: '*')),
            'internal_cost' => $internalCost,
            'commission_amount' => $commissionAmount,
            'base_price' => $basePrice,
            'gift_codes' => $giftCodes,
            'artist_codes' => $artistCodes,
            'other_cost_codes' => $otherCostCodes,
            'is_active' => (bool) $data['is_active'],
            'is_default' => (bool) $data['is_default'],
            'sort_order' => (int) ($data['sort_order'] ?? 100),
        ]);

        return $this->redirectAfterPackageMutation($request, (int) $serenataPackage->mariachi_group_id, 'Paquete actualizado correctamente.');
    }

    public function destroy(Request $request, SerenataPackage $serenataPackage)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        if (
            $organizationId <= 0
            || $serenataPackage->organization_id !== $organizationId
            || !OwnerWorkspace::canAccessGroup($request->user(), (int) $serenataPackage->mariachi_group_id)
        ) {
            abort(404);
        }

        $groupId = (int) $serenataPackage->mariachi_group_id;
        $serenataPackage->delete();
        return $this->redirectAfterPackageMutation($request, $groupId, 'Paquete eliminado correctamente.');
    }
}
