<?php

namespace Tests\Feature\CRMCore;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Modules\CRMCore\App\Models\Company;
use Modules\CRMCore\App\Models\Deal;
use Modules\CRMCore\App\Models\Lead;
use Modules\CRMCore\App\Models\LeadStatus;
use Modules\SystemCore\App\Enums\CustomerType;
use Modules\SystemCore\App\Models\CoreCustomer;
use Tests\TestCase;
use Tests\Traits\CreatesCRMCoreEntities;
use Tests\Traits\CreatesUsers;

class LeadConversionTest extends TestCase
{
    use CreatesCRMCoreEntities;
    use CreatesUsers;
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();

        if (! moduleExists('CRMCore')) {
            $this->markTestSkipped('CRMCore module is not enabled');
        }

        // Required for view rendering (app_logo, etc.)
        $this->ensureSettingsExist();
    }

    // ==========================================
    // Basic Conversion Tests
    // ==========================================

    public function test_convert_lead_creates_customer(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead([
            'title' => 'Hot Lead',
            'contact_name' => 'John Smith',
            'contact_email' => 'john@example.com',
            'contact_phone' => '+1234567890',
            'created_by_id' => $admin->id,
        ]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'John Smith',
            'customer_email' => 'john@example.com',
            'customer_phone' => '+1234567890',
            'company_option' => 'none',
            'create_deal' => false,
        ]);

        $response->assertStatus(200);
        $response->assertJson(['code' => 200]);

        // Verify customer was created
        $this->assertDatabaseHas('core_customers', [
            'name' => 'John Smith',
            'email' => 'john@example.com',
        ]);

        // Verify lead was marked as converted
        $lead->refresh();
        $this->assertNotNull($lead->converted_at);
        $this->assertNotNull($lead->converted_to_customer_id);
    }

    public function test_convert_lead_with_new_company(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead([
            'company_name' => 'Acme Inc',
            'created_by_id' => $admin->id,
        ]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Jane Doe',
            'customer_email' => 'jane@acme.com',
            'company_option' => 'new',
            'new_company_name' => 'Acme Corporation',
            'create_deal' => false,
        ]);

        $response->assertStatus(200);

        // Verify company was created
        $this->assertDatabaseHas('companies', [
            'name' => 'Acme Corporation',
        ]);

        // Verify customer has B2B type (company association)
        $customer = CoreCustomer::where('email', 'jane@acme.com')->first();
        $this->assertNotNull($customer);
        // customer_type is cast to enum, compare enum directly
        $this->assertEquals(CustomerType::B2B, $customer->customer_type);
    }

    public function test_convert_lead_with_existing_company(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $company = $this->createCompany(['name' => 'Existing Corp']);
        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Bob Wilson',
            'customer_email' => 'bob@existing.com',
            'company_option' => 'existing',
            'existing_company_id' => $company->id,
            'create_deal' => false,
        ]);

        $response->assertStatus(200);

        // Verify customer linked to existing company
        $customer = CoreCustomer::where('email', 'bob@existing.com')->first();
        $this->assertNotNull($customer);
        $this->assertEquals($company->id, $customer->company_id);
    }

    public function test_convert_lead_without_company_creates_b2c_customer(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Individual Customer',
            'customer_email' => 'individual@example.com',
            'company_option' => 'none',
            'create_deal' => false,
        ]);

        $response->assertStatus(200);

        $customer = CoreCustomer::where('email', 'individual@example.com')->first();
        $this->assertNotNull($customer);
        // customer_type is cast to enum, compare enum directly
        $this->assertEquals(CustomerType::B2C, $customer->customer_type);
    }

    // ==========================================
    // Deal Creation Tests
    // ==========================================

    public function test_convert_lead_with_deal_creates_deal(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $pipelineData = $this->createPipelineWithStages();
        $pipeline = $pipelineData['pipeline'];
        $stages = $pipelineData['stages'];

        $lead = $this->createLead([
            'value' => 25000.00,
            'created_by_id' => $admin->id,
        ]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Deal Customer',
            'customer_email' => 'deal@example.com',
            'company_option' => 'none',
            'create_deal' => true,
            'deal_title' => 'New Software License',
            'deal_value' => 25000.00,
            'deal_pipeline_id' => $pipeline->id,
            'deal_stage_id' => $stages['qualification']->id,
            'deal_expected_close_date' => now()->addMonth()->format('Y-m-d'),
        ]);

        $response->assertStatus(200);
        $response->assertJsonStructure(['deal_url']);

        // Verify deal was created
        $this->assertDatabaseHas('deals', [
            'title' => 'New Software License',
            'value' => 25000.00,
            'pipeline_id' => $pipeline->id,
        ]);

        // Verify lead linked to deal
        $lead->refresh();
        $this->assertNotNull($lead->converted_to_deal_id);
    }

    public function test_convert_lead_uses_default_stage_if_invalid_stage(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $pipelineData = $this->createPipelineWithStages();
        $pipeline = $pipelineData['pipeline'];
        $stages = $pipelineData['stages'];

        // Create another pipeline with different stages
        $otherPipeline = $this->createDealPipeline(['name' => 'Other Pipeline']);
        $otherStage = $this->createDealStage($otherPipeline, ['name' => 'Other Stage']);

        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Stage Test Customer',
            'customer_email' => 'stagetest@example.com',
            'company_option' => 'none',
            'create_deal' => true,
            'deal_title' => 'Stage Test Deal',
            'deal_value' => 1000.00,
            'deal_pipeline_id' => $pipeline->id,
            'deal_stage_id' => $otherStage->id, // Wrong pipeline stage
        ]);

        $response->assertStatus(200);

        // Deal should use default stage from correct pipeline
        $deal = Deal::where('title', 'Stage Test Deal')->first();
        $this->assertNotNull($deal);
        $this->assertEquals($pipeline->id, $deal->pipeline_id);
        $this->assertEquals($stages['qualification']->id, $deal->deal_stage_id);
    }

    public function test_deal_inherits_lead_assignee(): void
    {
        $admin = $this->createAdmin();
        $assignee = $this->createAdmin();
        $this->actingAs($admin);

        $pipelineData = $this->createPipelineWithStages();
        $pipeline = $pipelineData['pipeline'];
        $stages = $pipelineData['stages'];

        $lead = $this->createLead([
            'assigned_to_user_id' => $assignee->id,
            'created_by_id' => $admin->id,
        ]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Inherited Assignee',
            'customer_email' => 'inherited@example.com',
            'company_option' => 'none',
            'create_deal' => true,
            'deal_title' => 'Inherited Deal',
            'deal_value' => 5000.00,
            'deal_pipeline_id' => $pipeline->id,
            'deal_stage_id' => $stages['qualification']->id,
        ]);

        $response->assertStatus(200);

        $deal = Deal::where('title', 'Inherited Deal')->first();
        $this->assertNotNull($deal);
        $this->assertEquals($assignee->id, $deal->assigned_to_user_id);
    }

    // ==========================================
    // Status Update Tests
    // ==========================================

    public function test_lead_status_changes_to_converted(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $convertedStatus = $this->createConvertedLeadStatus();
        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Status Test',
            'customer_email' => 'status@example.com',
            'company_option' => 'none',
            'create_deal' => false,
        ]);

        $response->assertStatus(200);

        $lead->refresh();
        $this->assertEquals($convertedStatus->id, $lead->lead_status_id);
    }

    public function test_creates_converted_status_if_not_exists(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        // Ensure no "Converted" status exists
        LeadStatus::where('name', 'Converted')->delete();

        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Auto Status Test',
            'customer_email' => 'autostatus@example.com',
            'company_option' => 'none',
            'create_deal' => false,
        ]);

        $response->assertStatus(200);

        // Converted status should have been auto-created
        $this->assertDatabaseHas('lead_statuses', [
            'name' => 'Converted',
            'is_final' => true,
        ]);
    }

    // ==========================================
    // Validation Tests
    // ==========================================

    public function test_cannot_convert_already_converted_lead(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead([
            'converted_at' => now(),
            'created_by_id' => $admin->id,
        ]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Already Converted',
            'customer_email' => 'already@example.com',
            'company_option' => 'none',
            'create_deal' => false,
        ]);

        $response->assertStatus(400);
        $response->assertJson(['code' => 400]);
    }

    public function test_conversion_requires_customer_name(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_email' => 'noname@example.com',
            'company_option' => 'none',
            'create_deal' => false,
        ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['customer_name']);
    }

    public function test_new_company_requires_name(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Test Customer',
            'company_option' => 'new',
            // Missing new_company_name
            'create_deal' => false,
        ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['new_company_name']);
    }

    public function test_existing_company_requires_id(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Test Customer',
            'company_option' => 'existing',
            // Missing existing_company_id
            'create_deal' => false,
        ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['existing_company_id']);
    }

    public function test_deal_creation_requires_deal_fields(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Test Customer',
            'company_option' => 'none',
            'create_deal' => true,
            // Missing deal_title, deal_value, deal_pipeline_id, deal_stage_id
        ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['deal_title', 'deal_value', 'deal_pipeline_id', 'deal_stage_id']);
    }

    // ==========================================
    // Response Tests
    // ==========================================

    public function test_conversion_returns_customer_url(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'URL Test',
            'customer_email' => 'urltest@example.com',
            'company_option' => 'none',
            'create_deal' => false,
        ]);

        $response->assertStatus(200);
        $response->assertJsonStructure(['customer_url']);
    }

    public function test_conversion_with_company_returns_company_url(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead(['created_by_id' => $admin->id]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Company URL Test',
            'customer_email' => 'companyurl@example.com',
            'company_option' => 'new',
            'new_company_name' => 'New Corp',
            'create_deal' => false,
        ]);

        $response->assertStatus(200);
        $response->assertJsonStructure(['customer_url', 'company_url']);
    }

    // ==========================================
    // Edge Case Tests
    // ==========================================

    public function test_conversion_updates_existing_customer_if_email_exists(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        // Pre-create a customer with the same email
        CoreCustomer::create([
            'name' => 'Existing Customer',
            'email' => 'existing@example.com',
            'customer_type' => CustomerType::B2C->value,
            'created_by_id' => $admin->id,
        ]);

        $lead = $this->createLead([
            'contact_email' => 'existing@example.com',
            'created_by_id' => $admin->id,
        ]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'Updated Name',
            'customer_email' => 'existing@example.com',
            'customer_phone' => '+9876543210',
            'company_option' => 'none',
            'create_deal' => false,
        ]);

        $response->assertStatus(200);

        // Should have updated existing customer, not created new one
        $this->assertEquals(1, CoreCustomer::where('email', 'existing@example.com')->count());

        $customer = CoreCustomer::where('email', 'existing@example.com')->first();
        $this->assertEquals('Updated Name', $customer->name);
    }

    public function test_conversion_with_null_email_creates_new_customer(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $lead = $this->createLead([
            'contact_email' => null,
            'created_by_id' => $admin->id,
        ]);

        $response = $this->postJson(route('leads.processConversion', $lead->id), [
            'customer_name' => 'No Email Customer',
            'company_option' => 'none',
            'create_deal' => false,
        ]);

        $response->assertStatus(200);

        $this->assertDatabaseHas('core_customers', [
            'name' => 'No Email Customer',
        ]);
    }
}
