<?php

namespace Tests\Traits;

use Modules\CRMCore\App\Models\Company;
use Modules\CRMCore\App\Models\Deal;
use Modules\CRMCore\App\Models\DealPipeline;
use Modules\CRMCore\App\Models\DealStage;
use Modules\CRMCore\App\Models\Lead;
use Modules\CRMCore\App\Models\LeadSource;
use Modules\CRMCore\App\Models\LeadStatus;

/**
 * Helper trait for creating CRMCore test entities.
 */
trait CreatesCRMCoreEntities
{
    // ==========================================
    // Lead Status Methods
    // ==========================================

    protected function createLeadStatus(array $attributes = []): LeadStatus
    {
        return LeadStatus::create(array_merge([
            'name' => 'Test Status '.uniqid(),
            'color' => '#6c757d',
            'position' => LeadStatus::max('position') + 1,
            'is_default' => false,
            'is_final' => false,
        ], $attributes));
    }

    protected function createDefaultLeadStatus(array $attributes = []): LeadStatus
    {
        // Ensure no other default exists
        LeadStatus::where('is_default', true)->update(['is_default' => false]);

        return $this->createLeadStatus(array_merge([
            'name' => 'New',
            'is_default' => true,
        ], $attributes));
    }

    protected function createConvertedLeadStatus(array $attributes = []): LeadStatus
    {
        return $this->createLeadStatus(array_merge([
            'name' => 'Converted',
            'color' => '#2196f3',
            'is_final' => true,
        ], $attributes));
    }

    // ==========================================
    // Lead Source Methods
    // ==========================================

    protected function createLeadSource(array $attributes = []): LeadSource
    {
        return LeadSource::create(array_merge([
            'name' => 'Test Source '.uniqid(),
            'is_active' => true,
        ], $attributes));
    }

    // ==========================================
    // Lead Methods
    // ==========================================

    protected function createLead(array $attributes = []): Lead
    {
        // Ensure we have a default status
        $defaultStatus = LeadStatus::where('is_default', true)->first();
        if (! $defaultStatus) {
            $defaultStatus = $this->createDefaultLeadStatus();
        }

        return Lead::create(array_merge([
            'title' => 'Test Lead '.uniqid(),
            'description' => 'Test lead description',
            'contact_name' => 'John Doe',
            'contact_email' => 'lead'.uniqid().'@example.com',
            'contact_phone' => '+1234567890',
            'company_name' => 'Test Company',
            'value' => 5000.00,
            'lead_status_id' => $defaultStatus->id,
        ], $attributes));
    }

    protected function createLeadWithSource(array $attributes = []): Lead
    {
        $source = $this->createLeadSource();

        return $this->createLead(array_merge([
            'lead_source_id' => $source->id,
        ], $attributes));
    }

    protected function createAssignedLead(array $attributes = []): Lead
    {
        return $this->createLead($attributes);
    }

    // ==========================================
    // Deal Pipeline Methods
    // ==========================================

    protected function createDealPipeline(array $attributes = []): DealPipeline
    {
        return DealPipeline::create(array_merge([
            'name' => 'Test Pipeline '.uniqid(),
            'description' => 'Test pipeline description',
            'is_default' => false,
            'is_active' => true,
            'position' => DealPipeline::max('position') + 1,
        ], $attributes));
    }

    protected function createDefaultDealPipeline(array $attributes = []): DealPipeline
    {
        // Ensure no other default exists
        DealPipeline::where('is_default', true)->update(['is_default' => false]);

        return $this->createDealPipeline(array_merge([
            'name' => 'Sales Pipeline',
            'is_default' => true,
        ], $attributes));
    }

    // ==========================================
    // Deal Stage Methods
    // ==========================================

    protected function createDealStage(DealPipeline $pipeline, array $attributes = []): DealStage
    {
        return DealStage::create(array_merge([
            'pipeline_id' => $pipeline->id,
            'name' => 'Test Stage '.uniqid(),
            'color' => '#6c757d',
            'position' => DealStage::where('pipeline_id', $pipeline->id)->max('position') + 1,
            'is_default_for_pipeline' => false,
            'is_won_stage' => false,
            'is_lost_stage' => false,
        ], $attributes));
    }

    protected function createDefaultDealStage(DealPipeline $pipeline, array $attributes = []): DealStage
    {
        // Ensure no other default exists for this pipeline
        DealStage::where('pipeline_id', $pipeline->id)
            ->where('is_default_for_pipeline', true)
            ->update(['is_default_for_pipeline' => false]);

        return $this->createDealStage($pipeline, array_merge([
            'name' => 'Qualification',
            'is_default_for_pipeline' => true,
        ], $attributes));
    }

    protected function createWonDealStage(DealPipeline $pipeline, array $attributes = []): DealStage
    {
        return $this->createDealStage($pipeline, array_merge([
            'name' => 'Won',
            'color' => '#28a745',
            'is_won_stage' => true,
            'position' => 99,
        ], $attributes));
    }

    protected function createLostDealStage(DealPipeline $pipeline, array $attributes = []): DealStage
    {
        return $this->createDealStage($pipeline, array_merge([
            'name' => 'Lost',
            'color' => '#dc3545',
            'is_lost_stage' => true,
            'position' => 100,
        ], $attributes));
    }

    /**
     * Create a pipeline with full stages.
     *
     * @return array{pipeline: DealPipeline, stages: array<string, DealStage>}
     */
    protected function createPipelineWithStages(array $attributes = []): array
    {
        $pipeline = $this->createDefaultDealPipeline($attributes);

        $stages = [
            'qualification' => $this->createDefaultDealStage($pipeline, ['name' => 'Qualification', 'position' => 1]),
            'meeting' => $this->createDealStage($pipeline, ['name' => 'Meeting Scheduled', 'position' => 2]),
            'proposal' => $this->createDealStage($pipeline, ['name' => 'Proposal Sent', 'position' => 3]),
            'negotiation' => $this->createDealStage($pipeline, ['name' => 'Negotiation', 'position' => 4]),
            'won' => $this->createWonDealStage($pipeline, ['position' => 5]),
            'lost' => $this->createLostDealStage($pipeline, ['position' => 6]),
        ];

        return ['pipeline' => $pipeline, 'stages' => $stages];
    }

    // ==========================================
    // Company Methods
    // ==========================================

    protected function createCompany(array $attributes = []): Company
    {
        return Company::create(array_merge([
            'name' => 'Test Company '.uniqid(),
            'website' => 'https://example.com',
            'industry' => 'Technology',
            'description' => 'Test company description',
        ], $attributes));
    }

    // ==========================================
    // Deal Methods
    // ==========================================

    protected function createDeal(array $attributes = []): Deal
    {
        // Ensure we have a pipeline and stage
        $pipeline = DealPipeline::where('is_active', true)->first();
        if (! $pipeline) {
            $pipeline = $this->createDefaultDealPipeline();
        }

        $stage = DealStage::where('pipeline_id', $pipeline->id)->first();
        if (! $stage) {
            $stage = $this->createDefaultDealStage($pipeline);
        }

        return Deal::create(array_merge([
            'title' => 'Test Deal '.uniqid(),
            'description' => 'Test deal description',
            'value' => 10000.00,
            'currency' => 'USD',
            'expected_close_date' => now()->addMonth(),
            'probability' => 50,
            'pipeline_id' => $pipeline->id,
            'deal_stage_id' => $stage->id,
        ], $attributes));
    }

    protected function createDealWithCustomer(array $attributes = []): Deal
    {
        // Uses the SystemCore trait method if available
        if (method_exists($this, 'createCoreCustomer')) {
            $admin = method_exists($this, 'createAdmin') ? $this->createAdmin() : null;
            $customer = $this->createCoreCustomer(['created_by_id' => $admin?->id]);

            return $this->createDeal(array_merge([
                'customer_id' => $customer->id,
            ], $attributes));
        }

        return $this->createDeal($attributes);
    }

    protected function createDealWithCompany(array $attributes = []): Deal
    {
        $company = $this->createCompany();

        return $this->createDeal(array_merge([
            'company_id' => $company->id,
        ], $attributes));
    }

    protected function createWonDeal(array $attributes = []): Deal
    {
        $pipeline = DealPipeline::where('is_active', true)->first();
        if (! $pipeline) {
            $pipeline = $this->createDefaultDealPipeline();
        }

        $wonStage = DealStage::where('pipeline_id', $pipeline->id)->where('is_won_stage', true)->first();
        if (! $wonStage) {
            $wonStage = $this->createWonDealStage($pipeline);
        }

        return $this->createDeal(array_merge([
            'pipeline_id' => $pipeline->id,
            'deal_stage_id' => $wonStage->id,
            'won_at' => now(),
            'actual_close_date' => now(),
            'probability' => 100,
        ], $attributes));
    }

    protected function createLostDeal(array $attributes = []): Deal
    {
        $pipeline = DealPipeline::where('is_active', true)->first();
        if (! $pipeline) {
            $pipeline = $this->createDefaultDealPipeline();
        }

        $lostStage = DealStage::where('pipeline_id', $pipeline->id)->where('is_lost_stage', true)->first();
        if (! $lostStage) {
            $lostStage = $this->createLostDealStage($pipeline);
        }

        return $this->createDeal(array_merge([
            'pipeline_id' => $pipeline->id,
            'deal_stage_id' => $lostStage->id,
            'lost_at' => now(),
            'actual_close_date' => now(),
            'lost_reason' => 'Price too high',
            'probability' => 0,
        ], $attributes));
    }
}
