<?php

namespace App\Http\Controllers\Owner;

use App\Http\Controllers\Controller;
use App\Models\ExternalPartner;
use App\Models\ExternalPartnerMovement;
use App\Models\Serenata;
use Illuminate\Http\Request;

class ExternalPartnerController extends Controller
{
    private function ensureAccessiblePartner(Request $request, ExternalPartner $externalPartner): int
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        if ($organizationId <= 0 || $externalPartner->organization_id !== $organizationId) {
            abort(404);
        }

        return $organizationId;
    }

    public function index(Request $request)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        $canManage = $organizationId > 0;

        $items = $canManage
            ? ExternalPartner::query()
                ->where('organization_id', $organizationId)
                ->orderBy('sort_order')
                ->orderBy('name')
                ->get()
            : collect();

        return view('content.owner.settings.external-partners.index', [
            'canManageExternalPartners' => $canManage,
            'items' => $items,
            'stats' => [
                'total' => $items->count(),
                'active' => $items->where('is_active', true)->count(),
                'inactive' => $items->where('is_active', false)->count(),
            ],
        ]);
    }

    public function show(Request $request, ExternalPartner $externalPartner)
    {
        $organizationId = $this->ensureAccessiblePartner($request, $externalPartner);
        $perPage = 10;
        $queryParams = $request->query();
        $serenataSearch = trim((string) $request->query('serenatas_q', ''));
        $serenataStatus = trim((string) $request->query('serenatas_status', ''));
        $serenataPaymentStatus = trim((string) $request->query('serenatas_payment', ''));
        $movementSearch = trim((string) $request->query('movements_q', ''));
        $movementType = trim((string) $request->query('movements_type', ''));
        $movementDirection = trim((string) $request->query('movements_direction', ''));
        $movementSettlement = trim((string) $request->query('movements_settlement', ''));

        $serenatasBaseQuery = Serenata::query()
            ->where('organization_id', $organizationId)
            ->where(function ($query) use ($externalPartner) {
                $query
                    ->where('external_partner_id', $externalPartner->id)
                    ->orWhereHas('externalPartnerMovements', function ($movementQuery) use ($externalPartner) {
                        $movementQuery->where('external_partner_id', $externalPartner->id);
                    });
            });

        if ($serenataSearch !== '') {
            $serenatasBaseQuery->where(function ($query) use ($serenataSearch) {
                $like = '%' . $serenataSearch . '%';
                $query
                    ->where('code', 'like', $like)
                    ->orWhere('payer_name', 'like', $like)
                    ->orWhere('to_name', 'like', $like)
                    ->orWhere('reason', 'like', $like)
                    ->orWhere('service_address', 'like', $like);
            });
        }

        if ($serenataStatus !== '') {
            $serenatasBaseQuery->where('service_status', $serenataStatus);
        }

        if ($serenataPaymentStatus !== '') {
            $serenatasBaseQuery->where('payment_status', $serenataPaymentStatus);
        }

        $serenatas = (clone $serenatasBaseQuery)
            ->with('mariachiGroup:id,name')
            ->orderByDesc('event_date')
            ->orderByDesc('event_time')
            ->orderByDesc('id')
            ->paginate($perPage, ['*'], 'serenatas_page')
            ->appends($queryParams)
            ->fragment('external-serenatas');

        $movementsBaseQuery = ExternalPartnerMovement::query()
            ->with([
                'serenata:id,code,event_date,event_time,payer_name,to_name,total_charged,service_status,payment_status',
                'createdByUser:id,name',
            ])
            ->where('organization_id', $organizationId)
            ->where('external_partner_id', $externalPartner->id);

        if ($movementSearch !== '') {
            $movementsBaseQuery->where(function ($query) use ($movementSearch) {
                $like = '%' . $movementSearch . '%';
                $query
                    ->where('counterpart_reference', 'like', $like)
                    ->orWhere('notes', 'like', $like)
                    ->orWhereHas('serenata', function ($serenataQuery) use ($like) {
                        $serenataQuery
                            ->where('code', 'like', $like)
                            ->orWhere('payer_name', 'like', $like)
                            ->orWhere('to_name', 'like', $like);
                    });
            });
        }

        if ($movementType !== '' && array_key_exists($movementType, ExternalPartnerMovement::typeOptions())) {
            $movementsBaseQuery->where('movement_type', $movementType);
        }

        if ($movementDirection !== '' && array_key_exists($movementDirection, ExternalPartnerMovement::directionOptions())) {
            $movementsBaseQuery->where('direction', $movementDirection);
        }

        if ($movementSettlement !== '' && array_key_exists($movementSettlement, ExternalPartnerMovement::settlementOptions())) {
            $movementsBaseQuery->where('settlement_kind', $movementSettlement);
        }

        $movements = (clone $movementsBaseQuery)
            ->orderByDesc('due_date')
            ->orderByDesc('id')
            ->paginate($perPage, ['*'], 'movements_page')
            ->appends($queryParams)
            ->fragment('external-movements');

        $movementCollection = (clone $movementsBaseQuery)->get();
        $balance = ExternalPartnerMovement::summarizeBalance($movementCollection);

        $serenataStatusOptions = Serenata::query()
            ->where('organization_id', $organizationId)
            ->where(function ($query) use ($externalPartner) {
                $query
                    ->where('external_partner_id', $externalPartner->id)
                    ->orWhereHas('externalPartnerMovements', function ($movementQuery) use ($externalPartner) {
                        $movementQuery->where('external_partner_id', $externalPartner->id);
                    });
            })
            ->whereNotNull('service_status')
            ->where('service_status', '!=', '')
            ->distinct()
            ->orderBy('service_status')
            ->pluck('service_status')
            ->values();

        $serenataPaymentOptions = Serenata::query()
            ->where('organization_id', $organizationId)
            ->where(function ($query) use ($externalPartner) {
                $query
                    ->where('external_partner_id', $externalPartner->id)
                    ->orWhereHas('externalPartnerMovements', function ($movementQuery) use ($externalPartner) {
                        $movementQuery->where('external_partner_id', $externalPartner->id);
                    });
            })
            ->whereNotNull('payment_status')
            ->where('payment_status', '!=', '')
            ->distinct()
            ->orderBy('payment_status')
            ->pluck('payment_status')
            ->values();

        $stats = [
            'serenatas' => (int) (clone $serenatasBaseQuery)->count(),
            'movements' => (int) $movementCollection->count(),
            'cedidas' => (int) $movementCollection->where('movement_type', ExternalPartnerMovement::TYPE_CEDIDA)->count(),
            'cambios' => (int) $movementCollection->whereIn('movement_type', [
                ExternalPartnerMovement::TYPE_CAMBIO_INMEDIATO,
                ExternalPartnerMovement::TYPE_CAMBIO_PENDIENTE,
                ExternalPartnerMovement::TYPE_COMPENSACION_SERENATA,
            ])->count(),
            'balance' => $balance,
            'ultima_serenata' => Serenata::query()
                ->where('organization_id', $organizationId)
                ->where(function ($query) use ($externalPartner) {
                    $query
                        ->where('external_partner_id', $externalPartner->id)
                        ->orWhereHas('externalPartnerMovements', function ($movementQuery) use ($externalPartner) {
                            $movementQuery->where('external_partner_id', $externalPartner->id);
                        });
                })
                ->latest('event_date')
                ->latest('event_time')
                ->value('event_date'),
            'monto_movido' => (float) $movementCollection->sum('amount'),
        ];

        return view('content.owner.settings.external-partners.show', [
            'partner' => $externalPartner,
            'stats' => $stats,
            'serenatas' => $serenatas,
            'movements' => $movements,
            'serenataStatusOptions' => $serenataStatusOptions,
            'serenataPaymentOptions' => $serenataPaymentOptions,
            'movementTypeOptions' => ExternalPartnerMovement::typeOptions(),
            'movementDirectionOptions' => ExternalPartnerMovement::directionOptions(),
            'movementSettlementOptions' => ExternalPartnerMovement::settlementOptions(),
        ]);
    }

    public function store(Request $request)
    {
        $organizationId = (int) ($request->user()->organization_id ?? 0);
        if ($organizationId <= 0) {
            return redirect()->route('owner.settings.external-partners')->withErrors([
                'name' => 'Primero debes tener una organización asignada.',
            ]);
        }

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:150'],
            'contact_name' => ['nullable', 'string', 'max:120'],
            'phone' => ['nullable', 'string', 'max:30'],
            'email' => ['nullable', 'email', 'max:120'],
            'city' => ['nullable', 'string', 'max:120'],
            'notes' => ['nullable', 'string', 'max:1200'],
            'is_active' => ['required', 'boolean'],
            'sort_order' => ['nullable', 'integer', 'min:0', 'max:9999'],
        ]);

        ExternalPartner::create([
            'organization_id' => $organizationId,
            'name' => trim((string) $validated['name']),
            'contact_name' => trim((string) ($validated['contact_name'] ?? '')) ?: null,
            'phone' => trim((string) ($validated['phone'] ?? '')) ?: null,
            'email' => trim((string) ($validated['email'] ?? '')) ?: null,
            'city' => trim((string) ($validated['city'] ?? '')) ?: null,
            'notes' => trim((string) ($validated['notes'] ?? '')) ?: null,
            'sort_order' => (int) ($validated['sort_order'] ?? 100),
            'is_active' => (bool) $validated['is_active'],
        ]);

        return redirect()->route('owner.settings.external-partners')->with('status', 'Externo creado correctamente.');
    }

    public function update(Request $request, ExternalPartner $externalPartner)
    {
        $organizationId = $this->ensureAccessiblePartner($request, $externalPartner);

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:150'],
            'contact_name' => ['nullable', 'string', 'max:120'],
            'phone' => ['nullable', 'string', 'max:30'],
            'email' => ['nullable', 'email', 'max:120'],
            'city' => ['nullable', 'string', 'max:120'],
            'notes' => ['nullable', 'string', 'max:1200'],
            'is_active' => ['required', 'boolean'],
            'sort_order' => ['nullable', 'integer', 'min:0', 'max:9999'],
        ]);

        $externalPartner->update([
            'name' => trim((string) $validated['name']),
            'contact_name' => trim((string) ($validated['contact_name'] ?? '')) ?: null,
            'phone' => trim((string) ($validated['phone'] ?? '')) ?: null,
            'email' => trim((string) ($validated['email'] ?? '')) ?: null,
            'city' => trim((string) ($validated['city'] ?? '')) ?: null,
            'notes' => trim((string) ($validated['notes'] ?? '')) ?: null,
            'sort_order' => (int) ($validated['sort_order'] ?? $externalPartner->sort_order),
            'is_active' => (bool) $validated['is_active'],
        ]);

        return redirect()->route('owner.settings.external-partners')->with('status', 'Externo actualizado correctamente.');
    }

    public function deactivate(Request $request, ExternalPartner $externalPartner)
    {
        $this->ensureAccessiblePartner($request, $externalPartner);

        $externalPartner->update([
            'is_active' => !$externalPartner->is_active,
        ]);

        return back()->with('status', $externalPartner->is_active
            ? 'Externo activado correctamente.'
            : 'Externo inactivado correctamente.');
    }

    public function destroy(Request $request, ExternalPartner $externalPartner)
    {
        $this->ensureAccessiblePartner($request, $externalPartner);

        return back()->withErrors([
            'name' => 'Los externos ya no se eliminan. Usa la opción de activar o inactivar.',
        ]);
    }
}
