<?php

namespace Tests\Feature;

use App\Models\ApiToken;
use App\Models\MariachiGroup;
use App\Models\Organization;
use App\Models\PaymentMethod;
use App\Models\Role;
use App\Models\Serenata;
use App\Models\User;
use App\Support\Authorization\PermissionCatalog;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\PermissionRegistrar;
use Tests\TestCase;

class ApiSerenataIntegrationTest extends TestCase
{
    use RefreshDatabase;

    public function test_api_token_can_create_a_serenata(): void
    {
        [$user, $token, $group] = $this->makeApiUserWithPermission('create');

        PaymentMethod::query()->create([
            'organization_id' => $user->organization_id,
            'name' => 'Transferencia',
            'is_active' => true,
            'is_default' => true,
        ]);

        $response = $this->withHeaders([
            'Authorization' => 'Bearer '.$token,
            'Accept' => 'application/json',
            'Idempotency-Key' => 'chatwoot-1001',
        ])->postJson('/api/v1/serenatas', [
            'external_reference' => 'cw-1001',
            'mariachi_group_id' => $group->id,
            'payer_name' => 'Laura Gomez',
            'payer_email' => 'laura@example.com',
            'service_address' => 'Calle 123 #45-67',
            'neighborhood' => 'Chapinero',
            'locality' => 'Bogotá',
            'contact_phone_1' => '3001234567',
            'reason' => 'Cumpleaños',
            'from_name' => 'Carlos',
            'to_name' => 'Mamá',
            'event_date' => '2026-06-01',
            'event_time' => '20:30',
            'payment_method' => 'Transferencia',
            'base_price' => 250000,
            'discount_amount' => 10000,
        ]);

        $response->assertCreated()
            ->assertJsonPath('created', true)
            ->assertJsonPath('serenata.external_reference', 'cw-1001')
            ->assertJsonPath('serenata.total_charged', 240000);

        $this->assertDatabaseHas('serenatas', [
            'organization_id' => $user->organization_id,
            'external_reference' => 'cw-1001',
            'payer_name' => 'Laura Gomez',
        ]);
    }

    public function test_external_reference_makes_creation_idempotent(): void
    {
        [$user, $token, $group] = $this->makeApiUserWithPermission('create');

        PaymentMethod::query()->create([
            'organization_id' => $user->organization_id,
            'name' => 'Transferencia',
            'is_active' => true,
            'is_default' => true,
        ]);

        Serenata::query()->create([
            'organization_id' => $user->organization_id,
            'created_by_user_id' => $user->id,
            'mariachi_group_id' => $group->id,
            'sequence' => 1001,
            'code' => $group->serenataCodePrefix().'-1001',
            'external_reference' => 'cw-2001',
            'payer_name' => 'Cliente Existente',
            'service_address' => 'Calle 10',
            'neighborhood' => 'Centro',
            'locality' => 'Bogotá',
            'contact_phone_1' => '+573001234567',
            'reason' => 'Aniversario',
            'from_name' => 'Ana',
            'to_name' => 'Luis',
            'event_date' => '2026-06-01',
            'event_time' => '19:00',
            'base_price' => 200000,
            'gift_amount' => 0,
            'artist_amount' => 0,
            'other_cost_amount' => 0,
            'discount_amount' => 0,
            'base_cost' => 0,
            'total_charged' => 200000,
            'profit_amount' => 200000,
            'commission_rate' => 0,
            'commission_amount' => 200000,
            'payment_status' => 'Pendiente',
            'service_status' => 'Pendiente',
            'payment_method' => 'Transferencia',
            'ceded_amount' => 0,
        ]);

        $response = $this->withHeaders([
            'Authorization' => 'Bearer '.$token,
            'Accept' => 'application/json',
        ])->postJson('/api/v1/serenatas', [
            'external_reference' => 'cw-2001',
            'mariachi_group_id' => $group->id,
            'payer_name' => 'Otro Nombre',
            'service_address' => 'Otra calle',
            'neighborhood' => 'Centro',
            'locality' => 'Bogotá',
            'contact_phone_1' => '3001234567',
            'reason' => 'Cumpleaños',
            'from_name' => 'Carlos',
            'to_name' => 'Mamá',
            'event_date' => '2026-06-01',
            'event_time' => '20:30',
            'base_price' => 250000,
        ]);

        $response->assertOk()
            ->assertJsonPath('created', false)
            ->assertJsonPath('serenata.external_reference', 'cw-2001')
            ->assertJsonPath('serenata.payer_name', 'Cliente Existente');

        $this->assertSame(1, Serenata::query()->where('external_reference', 'cw-2001')->count());
    }

    public function test_search_serenatas_by_phone_matches_both_phone_fields(): void
    {
        [$user, $token, $group] = $this->makeApiUserWithPermission('view');

        $matchingPrimary = $this->makeSerenata($user, $group, [
            'sequence' => 1001,
            'code' => $group->serenataCodePrefix().'-1001',
            'payer_name' => 'Cliente Uno',
            'contact_phone_1' => '+573001234567',
            'contact_phone_2' => null,
            'event_date' => '2026-06-15',
            'event_time' => '21:00',
        ]);

        $matchingSecondary = $this->makeSerenata($user, $group, [
            'sequence' => 1002,
            'code' => $group->serenataCodePrefix().'-1002',
            'payer_name' => 'Cliente Dos',
            'contact_phone_1' => '+573009999999',
            'contact_phone_2' => '+573001234567',
            'event_date' => '2026-06-16',
            'event_time' => '20:00',
        ]);

        $this->makeSerenata($user, $group, [
            'sequence' => 1003,
            'code' => $group->serenataCodePrefix().'-1003',
            'payer_name' => 'Cliente Tres',
            'contact_phone_1' => '+573004444444',
            'event_date' => '2026-06-17',
            'event_time' => '19:00',
        ]);

        $response = $this->withHeaders([
            'Authorization' => 'Bearer '.$token,
            'Accept' => 'application/json',
        ])->getJson('/api/v1/serenatas?phone=3001234567');

        $response->assertOk()
            ->assertJsonPath('meta.count', 2)
            ->assertJsonPath('meta.filters.phone', '3001234567')
            ->assertJsonPath('serenatas.0.id', $matchingSecondary->id)
            ->assertJsonPath('serenatas.1.id', $matchingPrimary->id);
    }

    public function test_search_serenatas_by_email_and_limit_returns_summary_rows(): void
    {
        [$user, $token, $group] = $this->makeApiUserWithPermission('view');

        $newest = $this->makeSerenata($user, $group, [
            'sequence' => 1001,
            'code' => $group->serenataCodePrefix().'-1001',
            'payer_name' => 'Cliente Uno',
            'payer_email' => 'cliente@example.com',
            'contact_phone_1' => '+573001111111',
            'event_date' => '2026-06-21',
            'event_time' => '21:30',
        ]);

        $this->makeSerenata($user, $group, [
            'sequence' => 1002,
            'code' => $group->serenataCodePrefix().'-1002',
            'payer_name' => 'Cliente Dos',
            'payer_email' => 'cliente@example.com',
            'contact_phone_1' => '+573002222222',
            'event_date' => '2026-06-20',
            'event_time' => '20:30',
        ]);

        $response = $this->withHeaders([
            'Authorization' => 'Bearer '.$token,
            'Accept' => 'application/json',
        ])->getJson('/api/v1/serenatas?email=CLIENTE@example.com&limit=1');

        $response->assertOk()
            ->assertJsonPath('meta.count', 1)
            ->assertJsonPath('meta.limit', 1)
            ->assertJsonPath('serenatas.0.id', $newest->id)
            ->assertJsonPath('serenatas.0.payer_email', 'cliente@example.com')
            ->assertJsonMissingPath('serenatas.0.service_address');
    }

    public function test_search_serenatas_requires_at_least_one_filter(): void
    {
        [, $token] = $this->makeApiUserWithPermission('view');

        $this->withHeaders([
            'Authorization' => 'Bearer '.$token,
            'Accept' => 'application/json',
        ])->getJson('/api/v1/serenatas')
            ->assertUnprocessable()
            ->assertJsonValidationErrors(['filters']);
    }

    public function test_api_docs_require_a_valid_token(): void
    {
        $this->get('/api/v1/docs')->assertUnauthorized();
        $this->getJson('/api/v1/openapi.json')->assertUnauthorized();
    }

    public function test_api_docs_can_be_opened_with_query_token(): void
    {
        [, $token] = $this->makeApiUserWithPermission('view');

        $this->getJson('/api/v1/docs?api_token='.urlencode($token))
            ->assertOk()
            ->assertJsonPath('openapi', '3.1.0')
            ->assertJsonPath('x-agent-entrypoint.documentation_url', 'http://localhost/api/v1/docs?api_token=<TOKEN_API>')
            ->assertJsonPath('paths./api/v1/serenatas.post.summary', 'Crear serenata');

        $this->getJson('/api/v1/openapi.json?api_token='.urlencode($token))
            ->assertOk()
            ->assertJsonPath('openapi', '3.1.0')
            ->assertJsonPath('paths./api/v1/serenatas.post.summary', 'Crear serenata')
            ->assertJsonPath('components.securitySchemes.bearerAuth.scheme', 'bearer');
    }

    private function makeApiUserWithPermission(string $action): array
    {
        app(PermissionRegistrar::class)->forgetCachedPermissions();

        $organization = Organization::query()->create([
            'name' => 'Mariachis Test',
            'entity_type' => 'ORGANIZATION',
            'contact_phone' => '3000000000',
            'city' => 'Bogotá',
            'country_code' => 'CO',
            'is_active' => true,
        ]);

        $group = MariachiGroup::ensureDefaultForOrganization((int) $organization->id);

        $user = User::query()->create([
            'name' => 'API User',
            'email' => 'api@example.com',
            'password' => 'secret',
            'role' => User::ROLE_CLIENT,
            'organization_id' => $organization->id,
            'has_all_mariachi_groups' => true,
            'is_active' => true,
        ]);

        $permissionName = PermissionCatalog::permissionName(PermissionCatalog::PANEL_OWNER, 'serenatas', $action);
        Permission::findOrCreate($permissionName, 'web');

        $role = Role::query()->create([
            'name' => 'API Serenatas '.$action,
            'code' => 'api_serenatas_'.$action.'_'.$organization->id,
            'guard_name' => 'web',
            'organization_id' => $organization->id,
            'is_system' => false,
            'is_active' => true,
        ]);
        $role->givePermissionTo($permissionName);

        setPermissionsTeamId((int) $organization->id);
        $user->assignRole($role);

        [, $plainTextToken] = ApiToken::issueForUser($user, 'n8n');

        return [$user, $plainTextToken, $group];
    }

    private function makeSerenata(User $user, MariachiGroup $group, array $overrides = []): Serenata
    {
        return Serenata::query()->create(array_merge([
            'organization_id' => $user->organization_id,
            'created_by_user_id' => $user->id,
            'mariachi_group_id' => $group->id,
            'sequence' => 1001,
            'code' => $group->serenataCodePrefix().'-1001',
            'external_reference' => null,
            'payer_name' => 'Cliente Base',
            'payer_email' => null,
            'service_address' => 'Calle 10',
            'neighborhood' => 'Centro',
            'locality' => 'Bogotá',
            'contact_phone_1' => '+573001234567',
            'contact_phone_2' => null,
            'reason' => 'Aniversario',
            'from_name' => 'Ana',
            'to_name' => 'Luis',
            'event_date' => '2026-06-01',
            'event_time' => '19:00',
            'base_price' => 200000,
            'gift_amount' => 0,
            'artist_amount' => 0,
            'other_cost_amount' => 0,
            'discount_amount' => 0,
            'base_cost' => 0,
            'total_charged' => 200000,
            'profit_amount' => 200000,
            'commission_rate' => 0,
            'commission_amount' => 200000,
            'payment_status' => 'Pendiente',
            'service_status' => 'Pendiente',
            'payment_method' => 'Transferencia',
            'ceded_amount' => 0,
        ], $overrides));
    }
}
