<?php

declare(strict_types=1);

namespace Tests\Unit\Services;

use App\Services\LeadService;
use Tests\TestCase;

class LeadManagementServiceTest extends TestCase
{
    private LeadService $leadService;
    private int $userId;
    private int $adminId;
    private int $eventId;

    protected function setUp(): void
    {
        parent::setUp();
        $this->leadService = new LeadService();
        $this->userId = $this->createTestUser('gestor@test.com', 'comercial_manager', 'active');
        $this->adminId = $this->createTestUser('admin@test.com', 'super_admin', 'active');
        $this->eventId = $this->createTestEvent('Feria Management', $this->userId);

        $this->seedLossReasons();
    }

    private function seedLossReasons(): void
    {
        $db = \App\Models\Database::connect();
        $reasons = ['Precio', 'Competencia', 'Sin interés', 'No contactable', 'Presupuesto', 'Otro'];
        foreach ($reasons as $name) {
            $stmt = $db->prepare("INSERT INTO loss_reasons (name, status) VALUES (:name, 'active') ON DUPLICATE KEY UPDATE name=name");
            try { $stmt->execute(['name' => $name]); } catch (\Exception $e) {}
        }
    }

    private function createTestLead(string $email = 'lead@test.com'): array
    {
        return $this->leadService->createManual([
            'first_name' => 'Test',
            'last_name' => 'Lead',
            'email' => $email,
            'company' => 'TestCo',
        ], $this->userId, $this->eventId);
    }

    public function testGetLeads(): void
    {
        $this->createTestLead('lead1@test.com');
        $this->createTestLead('lead2@test.com');

        $result = $this->leadService->getLeads($this->userId, 'comercial_manager', [
            'event_id' => $this->eventId,
        ]);
        $this->assertGreaterThanOrEqual(2, $result['total']);
    }

    public function testGetLeadsSoftScopingGestor(): void
    {
        $this->createTestLead('gestor-lead@test.com');

        $this->leadService->createManual([
            'first_name' => 'Admin', 'last_name' => 'Lead', 'email' => 'admin-lead@test.com',
        ], $this->adminId, $this->eventId);

        $result = $this->leadService->getLeads($this->userId, 'comercial_manager', [
            'event_id' => $this->eventId,
        ]);
        $this->assertEquals(1, $result['total']);
    }

    public function testGetLeadsSuperAdminSeesAll(): void
    {
        $this->createTestLead('lead-a@test.com');
        $this->leadService->createManual([
            'first_name' => 'Admin', 'last_name' => 'Lead', 'email' => 'lead-b@test.com',
        ], $this->adminId, $this->eventId);

        $result = $this->leadService->getLeads($this->adminId, 'super_admin', [
            'event_id' => $this->eventId,
        ]);
        $this->assertEquals(2, $result['total']);
    }

    public function testGetLeadsWithFilters(): void
    {
        $this->createTestLead('filter-test@test.com');

        $this->leadService->changeStatus(
            $this->leadService->createManual([
                'first_name' => 'Contacted', 'last_name' => 'Lead', 'email' => 'contacted@test.com',
            ], $this->userId, $this->eventId)['id'],
            'contactado', null, null, $this->userId
        );

        $result = $this->leadService->getLeads($this->userId, 'comercial_manager', [
            'event_id' => $this->eventId,
            'status' => 'contactado',
        ]);
        $this->assertEquals(1, $result['total']);
    }

    public function testGetLeadsWithSearch(): void
    {
        $this->leadService->createManual([
            'first_name' => 'Carlos', 'last_name' => 'Buscado', 'email' => 'carlos@test.com',
        ], $this->userId, $this->eventId);

        $result = $this->leadService->getLeads($this->userId, 'comercial_manager', [
            'event_id' => $this->eventId,
            'search' => 'carlos',
        ]);
        $this->assertGreaterThanOrEqual(1, $result['total']);
    }

    public function testGetLeadsPagination(): void
    {
        for ($i = 1; $i <= 5; $i++) {
            $this->createTestLead("page{$i}@test.com");
        }

        $result = $this->leadService->getLeads($this->userId, 'comercial_manager', [
            'event_id' => $this->eventId,
        ], 1, 3);
        $this->assertCount(3, $result['items']);
        $this->assertEquals(3, $result['per_page']);
    }

    public function testGetLeadDetail(): void
    {
        $lead = $this->createTestLead('detail@test.com');

        $detail = $this->leadService->getLeadDetail($lead['id']);
        $this->assertEquals('detail@test.com', $detail['email']);
        $this->assertArrayHasKey('technical_profile', $detail);
        $this->assertArrayHasKey('status_history', $detail);
        $this->assertArrayHasKey('timeline', $detail);
    }

    public function testUpdateLead(): void
    {
        $lead = $this->createTestLead('update@test.com');

        $updated = $this->leadService->updateLead($lead['id'], [
            'first_name' => 'Actualizado',
            'company' => 'NuevaEmpresa',
            'technical_profile' => ['animal_type' => 'avícola'],
        ], $this->userId);

        $this->assertEquals('Actualizado', $updated['first_name']);
        $this->assertEquals('NuevaEmpresa', $updated['company']);
        $this->assertEquals('avícola', $updated['technical_profile']['animal_type']);
    }

    public function testChangeStatus(): void
    {
        $lead = $this->createTestLead('status@test.com');
        $this->assertEquals('nuevo', $lead['status']);

        $updated = $this->leadService->changeStatus(
            $lead['id'], 'contactado', null, 'Llamada realizada', $this->userId
        );

        $this->assertEquals('contactado', $updated['status']);
        $this->assertCount(1, $updated['status_history']);
        $this->assertEquals('nuevo', $updated['status_history'][0]['previous_status']);
        $this->assertEquals('contactado', $updated['status_history'][0]['new_status']);
    }

    public function testChangeStatusToLostRequiresReason(): void
    {
        $lead = $this->createTestLead('lost@test.com');

        $this->expectException(\RuntimeException::class);
        $this->expectExceptionMessage('Debe seleccionar un motivo');

        $this->leadService->changeStatus($lead['id'], 'perdido', null, null, $this->userId);
    }

    public function testChangeStatusToLostWithReason(): void
    {
        $lead = $this->createTestLead('lost-reason@test.com');

        $updated = $this->leadService->changeStatus(
            $lead['id'], 'perdido', 1, 'Precio muy alto', $this->userId
        );

        $this->assertEquals('perdido', $updated['status']);
    }

    public function testChangeStatusSameStatus(): void
    {
        $lead = $this->createTestLead('same@test.com');

        $this->leadService->changeStatus($lead['id'], 'contactado', null, null, $this->userId);

        $this->expectException(\RuntimeException::class);
        $this->leadService->changeStatus($lead['id'], 'contactado', null, null, $this->userId);
    }

    public function testChangeStatusInvalidStatus(): void
    {
        $lead = $this->createTestLead('invalid@test.com');

        $this->expectException(\RuntimeException::class);
        $this->leadService->changeStatus($lead['id'], 'estado_falso', null, null, $this->userId);
    }

    public function testChangeStatusToWon(): void
    {
        $lead = $this->createTestLead('won@test.com');

        $updated = $this->leadService->changeStatus(
            $lead['id'], 'ganado', null, 'Cliente confirmó', $this->userId
        );

        $this->assertEquals('ganado', $updated['status']);
    }

    public function testFullPipelineFlow(): void
    {
        $lead = $this->createTestLead('pipeline@test.com');

        $lead = $this->leadService->changeStatus($lead['id'], 'contactado', null, 'Primer contacto', $this->userId);
        $this->assertEquals('contactado', $lead['status']);

        $lead = $this->leadService->changeStatus($lead['id'], 'calificado', null, null, $this->userId);
        $this->assertEquals('calificado', $lead['status']);

        $lead = $this->leadService->changeStatus($lead['id'], 'propuesta', null, null, $this->userId);
        $this->assertEquals('propuesta', $lead['status']);

        $lead = $this->leadService->changeStatus($lead['id'], 'negociacion', null, null, $this->userId);
        $this->assertEquals('negociacion', $lead['status']);

        $lead = $this->leadService->changeStatus($lead['id'], 'ganado', null, 'Cerrado exitoso', $this->userId);
        $this->assertEquals('ganado', $lead['status']);

        $this->assertCount(5, $lead['status_history']);
    }

    public function testGetLossReasons(): void
    {
        $reasons = $this->leadService->getLossReasons();
        $this->assertGreaterThanOrEqual(1, count($reasons));
    }
}
