<?php

namespace Tests\Feature;

use App\Http\Controllers\Owner\SerenataController;
use App\Models\MariachiGroup;
use App\Models\Organization;
use App\Models\Serenata;
use App\Models\SerenataPayment;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Request;
use Tests\TestCase;

class OwnerSerenataCededSyncTest extends TestCase
{
    use RefreshDatabase;

    public function test_editing_cost_items_keeps_customer_charge_and_resyncs_ceded_breakdown(): void
    {
        [$user, $serenata] = $this->makeOwnerAndSerenata([
            'artist_items' => [
                [
                    'name' => 'Voz principal',
                    'quantity' => 1,
                    'unit_price' => 30000,
                    'charge_amount' => 30000,
                    'total' => 30000,
                    'is_deleted' => false,
                ],
            ],
            'gift_items' => [
                [
                    'name' => 'Chocolates',
                    'quantity' => 1,
                    'unit_price' => 4000,
                    'charge_amount' => 4000,
                    'total' => 4000,
                    'is_deleted' => false,
                ],
            ],
            'base_price' => 250000,
            'total_charged' => 250000,
            'base_cost' => 34000,
            'profit_amount' => 216000,
            'is_ceded' => true,
            'ceded_total_cost' => 34000,
            'ceded_artist_amount' => 30000,
            'ceded_gift_amount' => 4000,
            'ceded_other_cost_amount' => 0,
            'ceded_transport_amount' => 0,
            'ceded_excess_amount' => 216000,
            'ceded_excess_status' => 'por_cobrar',
            'ceded_amount' => 216000,
            'ceded_cost_breakdown' => [
                [
                    'source' => 'artist',
                    'index' => 0,
                    'name' => 'Voz principal',
                    'quantity' => 1,
                    'unit_price' => 30000,
                    'included' => true,
                    'total' => 30000,
                ],
                [
                    'source' => 'gift',
                    'index' => 0,
                    'name' => 'Chocolates',
                    'quantity' => 1,
                    'unit_price' => 4000,
                    'included' => true,
                    'total' => 4000,
                ],
            ],
        ]);

        $request = Request::create('/owner/serenatas/' . $serenata->id . '/cost-item', 'PATCH', [
            'source' => 'artist',
            'index' => 0,
            'quantity' => 1,
            'unit_price' => 40000,
        ], [], [], [
            'HTTP_ACCEPT' => 'application/json',
            'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest',
        ]);
        $request->setUserResolver(fn () => $user);

        $response = app(SerenataController::class)->updateCostItem($request, $serenata);

        $payload = $response->getData(true);

        $this->assertSame(200, $response->getStatusCode());
        $this->assertSame(250000, (int) data_get($payload, 'financials.base_price'));
        $this->assertSame(250000, (int) data_get($payload, 'financials.total_charged'));
        $this->assertTrue((bool) data_get($payload, 'refresh_required'));

        $serenata->refresh();

        $this->assertSame(250000.0, (float) $serenata->base_price);
        $this->assertSame(250000.0, (float) $serenata->total_charged);
        $this->assertSame(40000.0, (float) $serenata->artist_amount);
        $this->assertSame(44000.0, (float) $serenata->base_cost);
        $this->assertSame(40000.0, (float) $serenata->ceded_artist_amount);
        $this->assertSame(44000.0, (float) $serenata->ceded_total_cost);
        $this->assertSame(206000.0, (float) $serenata->ceded_excess_amount);
        $this->assertSame('por_cobrar', (string) $serenata->ceded_excess_status);
        $this->assertSame(40000.0, (float) data_get($serenata->ceded_cost_breakdown, '0.unit_price'));
    }

    public function test_updating_pricing_recomputes_ceded_overview(): void
    {
        [$user, $serenata] = $this->makeOwnerAndSerenata([
            'base_price' => 250000,
            'discount_amount' => 0,
            'total_charged' => 250000,
            'base_cost' => 200000,
            'profit_amount' => 50000,
            'artist_amount' => 200000,
            'artist_items' => [
                [
                    'name' => 'Mariachi externo',
                    'quantity' => 1,
                    'unit_price' => 200000,
                    'charge_amount' => 200000,
                    'total' => 200000,
                    'is_deleted' => false,
                ],
            ],
            'is_ceded' => true,
            'ceded_total_cost' => 200000,
            'ceded_artist_amount' => 200000,
            'ceded_gift_amount' => 0,
            'ceded_other_cost_amount' => 0,
            'ceded_transport_amount' => 0,
            'ceded_excess_amount' => 50000,
            'ceded_excess_status' => 'por_cobrar',
            'ceded_amount' => 50000,
            'ceded_cost_breakdown' => [
                [
                    'source' => 'artist',
                    'index' => 0,
                    'name' => 'Mariachi externo',
                    'quantity' => 1,
                    'unit_price' => 200000,
                    'included' => true,
                    'total' => 200000,
                ],
            ],
        ]);

        $request = Request::create('/owner/serenatas/' . $serenata->id . '/pricing', 'PATCH', [
            'base_price' => '281.000',
            'discount_amount' => '0',
        ]);
        $request->setUserResolver(fn () => $user);

        $response = app(SerenataController::class)->updatePricing($request, $serenata);

        $this->assertTrue($response->isRedirect());

        $serenata->refresh();

        $this->assertSame(281000.0, (float) $serenata->base_price);
        $this->assertSame(281000.0, (float) $serenata->total_charged);
        $this->assertSame(81000.0, (float) $serenata->ceded_excess_amount);
        $this->assertSame(81000.0, (float) $serenata->ceded_amount);
        $this->assertSame('por_cobrar', (string) $serenata->ceded_excess_status);
    }

    public function test_updating_service_status_no_longer_auto_registers_cash_payment(): void
    {
        [$user, $serenata] = $this->makeOwnerAndSerenata([
            'payment_method' => 'Efectivo al finalizar',
            'payment_status' => 'Pendiente',
            'service_status' => 'Pendiente',
            'total_charged' => 250000,
        ]);

        $request = Request::create('/owner/serenatas/' . $serenata->id . '/status', 'PATCH', [
            'service_status' => 'Confirmada',
            'cancellation_reason' => '',
        ]);
        $request->setUserResolver(fn () => $user);

        $response = app(SerenataController::class)->updateStatus($request, $serenata);

        $this->assertTrue($response->isRedirect());

        $serenata->refresh();

        $this->assertSame('Confirmada', (string) $serenata->service_status);
        $this->assertSame('Pendiente', (string) $serenata->payment_status);
        $this->assertSame(0, SerenataPayment::query()->where('serenata_id', $serenata->id)->count());
    }

    public function test_actual_customer_charge_recomputes_profit_payment_status_and_ceded_overview(): void
    {
        [$user, $serenata] = $this->makeOwnerAndSerenata([
            'base_price' => 300000,
            'total_charged' => 300000,
            'base_cost' => 200000,
            'profit_amount' => 100000,
            'artist_amount' => 200000,
            'artist_items' => [
                [
                    'name' => 'Mariachi externo',
                    'quantity' => 1,
                    'unit_price' => 200000,
                    'charge_amount' => 200000,
                    'total' => 200000,
                    'is_deleted' => false,
                ],
            ],
            'is_ceded' => true,
            'ceded_total_cost' => 200000,
            'ceded_artist_amount' => 200000,
            'ceded_excess_amount' => 100000,
            'ceded_excess_status' => 'por_cobrar',
            'ceded_amount' => 100000,
            'ceded_cost_breakdown' => [
                [
                    'source' => 'artist',
                    'index' => 0,
                    'name' => 'Mariachi externo',
                    'quantity' => 1,
                    'unit_price' => 200000,
                    'included' => true,
                    'total' => 200000,
                ],
            ],
        ]);

        SerenataPayment::query()->create([
            'organization_id' => $serenata->organization_id,
            'serenata_id' => $serenata->id,
            'registered_by_user_id' => $user->id,
            'paid_at' => now(),
            'payment_method_name' => 'Efectivo',
            'amount' => 250000,
            'note' => null,
        ]);

        $request = Request::create('/owner/serenatas/' . $serenata->id . '/actual-customer-charge', 'PATCH', [
            'actual_customer_charge' => '250.000',
            'actual_customer_charge_notes' => 'Ajuste por incidencia en obsequios',
        ]);
        $request->setUserResolver(fn () => $user);

        $response = app(SerenataController::class)->updateActualCustomerCharge($request, $serenata);

        $this->assertTrue($response->isRedirect());

        $serenata->refresh();

        $this->assertSame(250000.0, (float) $serenata->actual_customer_charge);
        $this->assertSame(50000.0, (float) $serenata->profit_amount);
        $this->assertSame(50000.0, (float) $serenata->ceded_excess_amount);
        $this->assertSame(50000.0, (float) $serenata->ceded_amount);
        $this->assertSame('Pagado', (string) $serenata->payment_status);
        $this->assertSame('Ajuste por incidencia en obsequios', (string) $serenata->actual_customer_charge_notes);
    }

    public function test_cancelled_service_without_payments_gets_cancelled_unpaid_payment_status(): void
    {
        [$user, $serenata] = $this->makeOwnerAndSerenata([
            'payment_status' => 'Pendiente',
            'service_status' => 'Pendiente',
        ]);

        $request = Request::create('/owner/serenatas/' . $serenata->id . '/status', 'PATCH', [
            'service_status' => 'Cancelada',
            'cancellation_reason' => 'Cliente canceló el evento',
        ]);
        $request->setUserResolver(fn () => $user);

        $response = app(SerenataController::class)->updateStatus($request, $serenata);

        $this->assertTrue($response->isRedirect());

        $serenata->refresh();

        $this->assertSame('Cancelada', (string) $serenata->service_status);
        $this->assertSame('Cancelada sin cobro', (string) $serenata->payment_status);
    }

    public function test_refund_reduces_net_paid_and_marks_partial_payment_status(): void
    {
        [$user, $serenata] = $this->makeOwnerAndSerenata([
            'payment_status' => 'Pagado',
            'service_status' => 'Realizada',
            'total_charged' => 250000,
        ]);

        SerenataPayment::query()->create([
            'organization_id' => $serenata->organization_id,
            'serenata_id' => $serenata->id,
            'registered_by_user_id' => $user->id,
            'paid_at' => now(),
            'payment_method_name' => 'Efectivo',
            'amount' => 250000,
            'note' => null,
        ]);

        $request = Request::create('/owner/serenatas/' . $serenata->id . '/refund', 'POST', [
            'refunded_at' => now()->format('Y-m-d H:i:s'),
            'amount' => 50000,
            'reason' => 'Descuento por incumplimiento',
        ]);
        $request->setUserResolver(fn () => $user);

        $response = app(SerenataController::class)->addRefund($request, $serenata);

        $this->assertTrue($response->isRedirect());

        $serenata->refresh();

        $this->assertSame('Abono parcial', (string) $serenata->payment_status);
        $this->assertSame(200000.0, (float) SerenataPayment::query()->where('serenata_id', $serenata->id)->sum('amount'));
    }

    private function makeOwnerAndSerenata(array $serenataOverrides = []): array
    {
        $organization = Organization::query()->create([
            'name' => 'Org Test',
        ]);

        $group = MariachiGroup::query()->create([
            'organization_id' => $organization->id,
            'code' => 'grupo_test',
            'name' => 'Grupo Test',
            'is_active' => true,
            'is_default' => true,
            'sort_order' => 1,
        ]);

        $user = User::factory()->create([
            'organization_id' => $organization->id,
            'role' => User::ROLE_OWNER_STAFF,
            'has_all_mariachi_groups' => true,
            'is_active' => true,
        ]);

        $serenata = Serenata::query()->create(array_merge([
            'organization_id' => $organization->id,
            'created_by_user_id' => $user->id,
            'mariachi_group_id' => $group->id,
            'sequence' => 1,
            'code' => 'SRA-001',
            'payer_name' => 'Cliente Test',
            'service_address' => 'Calle 123',
            'neighborhood' => 'Barrio Test',
            'locality' => 'Bogotá',
            'contact_phone_1' => '3001234567',
            'reason' => 'Cumpleaños',
            'from_name' => 'Ana',
            'to_name' => 'Luis',
            'event_date' => '2026-05-21',
            'event_time' => '20:00',
            'base_price' => 250000,
            'gift_amount' => 0,
            'gift_items' => [],
            'artist_amount' => 0,
            'artist_items' => [],
            'other_cost_amount' => 0,
            'other_cost_items' => [],
            'discount_amount' => 0,
            'base_cost' => 0,
            'total_charged' => 250000,
            'profit_amount' => 250000,
            'commission_rate' => 0,
            'commission_amount' => 250000,
            'payment_status' => 'Pendiente',
            'service_status' => 'Pendiente',
            'payment_method' => 'Efectivo',
            'ceded_amount' => 0,
            'is_ceded' => false,
            'ceded_total_cost' => 0,
            'ceded_artist_amount' => 0,
            'ceded_gift_amount' => 0,
            'ceded_transport_amount' => 0,
            'ceded_other_cost_amount' => 0,
            'ceded_excess_amount' => 0,
            'ceded_excess_status' => 'equilibrado',
            'ceded_cost_breakdown' => [],
        ], $serenataOverrides));

        return [$user, $serenata];
    }
}
