<?php

namespace App\Http\Controllers;

use App\Models\Activity;
use App\Models\Company;
use App\Models\Contact;
use App\Models\ContactEmail;
use App\Models\ContactLanguage;
use App\Models\ContactPhoneNum;
use App\Models\ContactSocialMedia;
use App\Models\Country;
use App\Models\Language;
use App\Models\Lead;
use App\Models\LeadStage;
use App\Models\LeadStageStatus;
use App\Models\MeetingThirdPartyIntegration;
use App\Models\Note;
use App\Models\Priority;
use App\Models\Repeat;
use App\Models\Stage;
use App\Models\Status;
use App\Models\User;
use App\Models\UserAccess;
use App\Models\AccessType;
use App\Models\WonLost;
use App\Models\Deal;
use App\Models\Project;
use App\Models\Product;
use App\Models\TradeDocument;
use App\Support\CrmAccess;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Illuminate\Validation\Rule;
use App\Services\CrmNotificationService;
use App\Services\ReportExportService;

class LeadController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');

        $this->middleware('permission:list_leads')->only(['index']);
        $this->middleware('permission:list_leads')->only(['show']);
        $this->middleware('permission:create_leads')->only(['create', 'store']);
        $this->middleware('permission:update_leads')->only(['edit', 'update', 'updateProfileField', 'addProduct', 'removeProduct', 'updateLeadStage', 'updateStage', 'updateStageStatus']);
        $this->middleware('permission:assign_leads')->only(['assignEmployee']);
        $this->middleware('permission:reopen_completed_leads')->only(['reopen']);
        $this->middleware('permission:delete_leads')->only(['destroy']);
    }
    
    public function index(Request $request)
    {
        $user = auth()->user();
        $businessId = $user->business_id;
        $this->useDefaultDateRange($request);

        $leadQuery = $this->getAccessibleLeads($user->id);
        $request->validate([
            'q'=>['nullable','string','max:100'],'status'=>['nullable',Rule::in(['active','inactive','completed'])],
            'stage_id'=>['nullable','integer'],'priority_id'=>['nullable','integer'],
            'date_from'=>['nullable','date'],'date_to'=>['nullable','date','after_or_equal:date_from'],
        ]);
        $search = trim((string) $request->input('q'));
        $leadQuery
        ->when($request->filled('status'),fn($q)=>$q->where('status',$request->status))
        ->when($request->filled('stage_id'),fn($q)=>$q->where('stage_id',$request->integer('stage_id')))
        ->when($request->filled('priority_id'),fn($q)=>$q->where('priority_id',$request->integer('priority_id')))
        ->when($request->filled('date_from'),fn($q)=>$q->whereDate('created_at','>=',$request->date_from))
        ->when($request->filled('date_to'),fn($q)=>$q->whereDate('created_at','<=',$request->date_to))
        ->when($search !== '', fn ($query) => $query->where(fn ($filter) => $filter
            ->where('topic', 'like', "%{$search}%")
            ->orWhere('first_name', 'like', "%{$search}%")
            ->orWhere('last_name', 'like', "%{$search}%")
            ->orWhere('job_title', 'like', "%{$search}%")));
        $todayLeadsCount = (clone $leadQuery)->whereDate('created_at', today())->count();
        $monthLeadsCount = (clone $leadQuery)->whereMonth('created_at', now()->month)->whereYear('created_at', now()->year)->count();
        $leadPaginator = (clone $leadQuery)->latest()->paginate(25)->withQueryString();
        $leads = collect($leadPaginator->items());

        // Today Leads
        $todayLeads = $leads->filter(function ($lead) {
            return $lead->created_at->isToday();
        });

        // This Month Leads
        $monthLeads = $leads->filter(function ($lead) {
            return $lead->created_at->isCurrentMonth();
        });

        $stages = LeadStage::active()->orderBy('id')->get(['id', 'name']);
        $activities = collect();
        $priorities = Priority::get(['id', 'name']);
        $countries = Country::get(['id', 'name']);
        $meetings = MeetingThirdPartyIntegration::get(['id', 'name']);
        $eventStatuses = Status::get(['id', 'name']);
        $companies = Company::get(['id', 'name']);
        $repeats = Repeat::get(['id', 'name']);
        $users = $this->getAccessibleUsers();
        $assignmentUsers = User::where('business_id', $businessId)
            ->orderBy('name')
            ->get(['id', 'name', 'email']);
        $contacts = Contact::where('business_id', $businessId)
            ->orderBy('first_name')->limit(250)->get(['id', 'first_name', 'last_name']);

        $wonStageIds = LeadStage::where('name', 'Qualified')->pluck('id')->toArray();
        $lostStageIds = LeadStage::where('name', 'Unqualified')->pluck('id')->toArray();

        // Get the latest stage status per deal
        $monthLeadWon = (clone $leadQuery)
            ->whereIn('stage_id', $wonStageIds)
            ->whereMonth('updated_at', now()->month)
            ->whereYear('updated_at', now()->year)
            ->count();

        $monthLeadLost = (clone $leadQuery)
            ->whereIn('stage_id', $lostStageIds)
            ->whereMonth('updated_at', now()->month)
            ->whereYear('updated_at', now()->year)
            ->count();


        $activityTypes = [
            1 => 'Call',
            2 => 'Appointment',
            3 => 'Task',
            4 => 'Event',
            5 => 'Deadline',
            6 => 'Other Activity',
            7 => 'Letter',
            8 => 'Fax',
            9 => 'Email',
            10 => 'Campaign',
        ];

        return view('leads.leads', compact(
            'leads', 
            'todayLeads', 
            'monthLeads',
            'monthLeadWon',
            'monthLeadLost', 
            'stages', 
            'activities', 
            'activityTypes', 
            'priorities', 
            'countries', 
            'meetings', 
            'eventStatuses', 
            'companies', 
            'repeats', 
            'contacts', 
            'users',
            'assignmentUsers',
            'leadPaginator',
            'todayLeadsCount',
            'monthLeadsCount'
        ));
    }

    public function options(Request $request)
    {
        $data = $request->validate(['q' => ['nullable', 'string', 'max:100']]);
        $search = trim((string) ($data['q'] ?? ''));
        $results = Lead::where('business_id', auth()->user()->business_id)
            ->whereNull('moved_at')
            ->when($search !== '', fn ($query) => $query->where(fn ($filter) => $filter
                ->where('topic', 'like', "%{$search}%")
                ->orWhere('first_name', 'like', "%{$search}%")
                ->orWhere('last_name', 'like', "%{$search}%")))
            ->latest('updated_at')
            ->limit(25)
            ->get(['id', 'topic', 'first_name', 'last_name'])
            ->map(fn ($lead) => [
                'id' => $lead->id,
                'text' => $lead->topic ?: trim($lead->first_name.' '.$lead->last_name),
            ]);

        return response()->json(['results' => $results]);
    }

    public function export(Request $request, ReportExportService $export, string $format)
    {
        abort_unless(in_array($format, ['pdf', 'csv', 'xml', 'txt', 'xlsx'], true), 404);
        $request->validate([
            'q' => ['nullable', 'string', 'max:100'],
            'status' => ['nullable', Rule::in(['active', 'inactive', 'completed'])],
            'stage_id' => ['nullable', 'integer'], 'priority_id' => ['nullable', 'integer'],
            'date_from' => ['nullable', 'date'], 'date_to' => ['nullable', 'date', 'after_or_equal:date_from'],
        ]);
        $search = trim((string) $request->input('q'));
        $query = $this->getAccessibleLeads(auth()->id())
            ->when($request->filled('status'), fn ($q) => $q->where('status', $request->status))
            ->when($request->filled('stage_id'), fn ($q) => $q->where('stage_id', $request->integer('stage_id')))
            ->when($request->filled('priority_id'), fn ($q) => $q->where('priority_id', $request->integer('priority_id')))
            ->when($request->filled('date_from'), fn ($q) => $q->whereDate('created_at', '>=', $request->date_from))
            ->when($request->filled('date_to'), fn ($q) => $q->whereDate('created_at', '<=', $request->date_to))
            ->when($search !== '', fn ($q) => $q->where(fn ($filter) => $filter
                ->where('topic', 'like', "%{$search}%")
                ->orWhere('first_name', 'like', "%{$search}%")
                ->orWhere('last_name', 'like', "%{$search}%")
                ->orWhere('job_title', 'like', "%{$search}%")));
        $headers = ['Topic', 'Name', 'Phone', 'Email', 'Owner', 'Stage', 'Priority', 'Status', 'Created'];
        $stages = LeadStage::active()->pluck('name', 'id');
        $priorities = Priority::pluck('name', 'id');
        $rows = $query->latest()->limit(10000)->get()->map(fn ($lead) => [
            $lead->topic,
            trim($lead->first_name.' '.$lead->last_name),
            $lead->contactPhones->first()?->phone,
            $lead->contactEmails->first()?->email,
            $lead->assignedUser?->name,
            $stages[$lead->stage_id] ?? '',
            $priorities[$lead->priority_id] ?? '',
            $lead->status,
            optional($lead->created_at)->format('Y-m-d H:i:s'),
        ])->all();
        $filename = 'leads-'.now()->format('Ymd-His');

        if ($format === 'pdf') {
            return response($export->pdf('Leads Export', $headers, $rows), 200, [
                'Content-Type' => 'application/pdf',
                'Content-Disposition' => "attachment; filename=\"{$filename}.pdf\"",
            ]);
        }
        if ($format === 'xlsx') {
            return response($export->xlsx('Leads', $headers, $rows), 200, [
                'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                'Content-Disposition' => "attachment; filename=\"{$filename}.xlsx\"",
            ]);
        }
        if ($format === 'xml') {
            $xml = '<?xml version="1.0" encoding="UTF-8"?><leads>';
            foreach ($rows as $row) {
                $xml .= '<lead>';
                foreach (array_combine($headers, $row) as $key => $value) {
                    $tag = strtolower(str_replace(' ', '_', $key));
                    $xml .= "<{$tag}>".htmlspecialchars((string) $value, ENT_XML1)."</{$tag}>";
                }
                $xml .= '</lead>';
            }
            return response($xml.'</leads>', 200, [
                'Content-Type' => 'application/xml',
                'Content-Disposition' => "attachment; filename=\"{$filename}.xml\"",
            ]);
        }
        if ($format === 'txt') {
            $lines = [implode("\t", $headers), ...array_map(fn ($row) => implode("\t", array_map(fn ($value) => str_replace(["\r", "\n", "\t"], ' ', (string) $value), $row)), $rows)];
            return response(implode(PHP_EOL, $lines), 200, [
                'Content-Type' => 'text/plain',
                'Content-Disposition' => "attachment; filename=\"{$filename}.txt\"",
            ]);
        }

        $handle = fopen('php://temp', 'r+');
        fputcsv($handle, $headers);
        foreach ($rows as $row) fputcsv($handle, $row);
        rewind($handle);
        $csv = stream_get_contents($handle);
        fclose($handle);
        return response($csv, 200, [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => "attachment; filename=\"{$filename}.csv\"",
        ]);
    }

    private function getAccessibleLeads($userId)
    {
        $accessibleUserIds = $this->getAccessibleUserIds($userId);
        
        return Lead::with([
            'contactPhones',
            'contactEmails',
            'contactSocialMedia',
            'contactLanguages.language',
            'assignedUser', 'company', 'country', 'priority',
            'latestActivity' => fn ($query) => $query->select('activities.*'),
        ])
            ->withCount([
                'activities',
                'activities as completed_activities_count' => fn ($query) => $query
                    ->where(fn ($status) => $status
                        ->where('lifecycle_status', 'completed')
                        ->orWhere('status', 'completed')),
            ])
            ->whereIn('contact_owner_id', $accessibleUserIds)
            ->where('business_id', auth()->user()->business_id)
            ->whereNull('moved_at');
    }

    private function getAccessibleUserIds($currentUserId)
    {
        return CrmAccess::accessibleUserIds(User::findOrFail($currentUserId));
    }

    private function getAccessibleUsers()
    {
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());
        return User::whereIn('id', $accessibleUserIds)->get();
    }

    public function assignEmployee(Request $request, int $id)
    {
        abort_unless(
            (bool) $request->user()->is_admin || $request->user()->can('assign_leads'),
            403
        );
        $lead = Lead::where('business_id', $request->user()->business_id)->findOrFail($id);
        abort_unless(
            in_array((int) $lead->contact_owner_id, array_map('intval', $this->getAccessibleUserIds($request->user()->id)), true),
            403
        );
        $this->assertLeadIsOpen($lead);

        $validated = $request->validate([
            'user_id' => [
                'required',
                'integer',
                Rule::notIn([(int) $lead->contact_owner_id]),
                Rule::exists('users', 'id')->where(fn ($query) => $query
                    ->where('business_id', $request->user()->business_id)),
            ],
        ], [
            'user_id.not_in' => 'Please select a different employee.',
        ]);

        $newOwner = User::where('business_id', $request->user()->business_id)
            ->findOrFail($validated['user_id']);

        \DB::transaction(function () use ($lead, $newOwner, $request) {
            $lead->update(['contact_owner_id' => $newOwner->id]);
            \DB::table('crm_assignment_histories')->insert([
                'business_id' => $lead->business_id,
                'assignable_type' => Lead::class,
                'assignable_id' => $lead->id,
                'user_id' => $newOwner->id,
                'changed_by' => $request->user()->id,
                'action' => 'reassigned',
                'created_at' => now(),
                'updated_at' => now(),
            ]);
        });

        app(CrmNotificationService::class)->assignment(
            $newOwner,
            $lead,
            'Lead',
            route('leads.view', ['id' => $lead->id])
        );

        return redirect()->route('leads')->with('success', "Lead assigned to {$newOwner->name}.");
    }

    public function updateLeadStage(Request $request, $id)
    {
        $lead = Lead::findOrFail($id);
        
        // Check access permission
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());
        
        if (!in_array($lead->contact_owner_id, $accessibleUserIds)) {
            abort(403, 'You do not have permission to update this lead.');
        }

        $this->assertLeadIsOpen($lead);

        $validated = $request->validate([
            'stage_id' => 'required|exists:lead_stages,id',
            'unqualified_reason' => 'nullable|required_if:stage_id,7|string|max:2000',
        ]);

        $currentStageId = $lead->stage_id;

        $lead->stage_id = $validated['stage_id'];
        $lead->status = in_array((int) $validated['stage_id'], [6, 7], true)
            ? 'completed'
            : 'active';
        $lead->unqualified_reason = (int) $validated['stage_id'] === 7 ? $validated['unqualified_reason'] : null;
        $lead->completed_at = in_array((int) $validated['stage_id'], [6, 7], true) ? now() : null;
        $lead->save();

        $this->notifyTerminalLeadStatus($lead, (int) $currentStageId);

        for ($i = 1; $i < $validated['stage_id']; $i++) {
            $leadStageStatus = LeadStageStatus::firstOrCreate([
                'lead_id' => $lead->id,
                'stage_id' => $i,
            ]);

            $leadStageStatus->stage_status = 3;
            $leadStageStatus->save();
        }

        $leadStageStatus = LeadStageStatus::firstOrCreate([
            'lead_id' => $lead->id,
            'stage_id' => $validated['stage_id'],
        ]);

        $leadStageStatus->stage_status = 1;
        $leadStageStatus->save();

        return response()->json([
            'message' => 'Lead Status updated successfully!',
            'stage_id' => (int) $lead->stage_id,
            'stage_name' => LeadStage::find($lead->stage_id)?->name,
            'completed' => in_array((int) $lead->stage_id, [6, 7], true),
            'record_status' => $lead->status,
            'action' => (int) $lead->stage_id === 6 ? 'convert' : ((int) $lead->stage_id === 7 ? 'close' : null),
            'conversion_url' => (int) $lead->stage_id === 6 ? route('leads.conversion-review', $lead->id) : null,
        ]);
    }


    public function updateStageStatus(Request $request)
    {
        $request->validate([
            'lead_id' => 'required|exists:leads,id',
            'stage_status' => 'required|in:1,2,3',
            'stage_id' => 'required|integer',
            'unqualified_reason' => 'nullable|required_if:stage_id,7|string|max:2000',
        ]);

        $lead = Lead::findOrFail($request->lead_id);
        $currentStageId = (int) $lead->stage_id;
        
        // Check access permission
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());
        
        if (!in_array($lead->contact_owner_id, $accessibleUserIds)) {
            abort(403, 'You do not have permission to update this lead.');
        }

        $this->assertLeadIsOpen($lead);

        $leadStageStatus = LeadStageStatus::updateOrCreate(
            ['lead_id' => $request->lead_id, 'stage_id' => $request->stage_id],
            ['stage_status' => $request->stage_status]
        );

        $highestStageId = LeadStageStatus::where('lead_id', $request->lead_id)
            ->max('stage_id');

        $highestStageStatus = LeadStageStatus::where('lead_id', $request->lead_id)
            ->where('stage_id', $highestStageId)
            ->value('stage_status');

        if ($highestStageStatus == 3) {
            if ($lead) {
                $lead->stage_id = $highestStageId;
                $lead->status = in_array((int) $highestStageId, [6, 7], true)
                    ? 'completed'
                    : 'active';
                $lead->unqualified_reason = (int) $highestStageId === 7 ? $request->unqualified_reason : null;
                $lead->completed_at = in_array((int) $highestStageId, [6, 7], true) ? now() : null;
                $lead->save();
                $this->notifyTerminalLeadStatus($lead, (int) $currentStageId);
            }
        }

        return response()->json([
            'success' => true,
            'message' => 'Lead Status updated successfully!',
        ]);
    }





    public function dashboard()
    {
        $stages = LeadStage::active()->orderBy('id')->get();
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());

        $dashboardLeads = Lead::with(['assignedUser', 'company', 'priority', 'contactEmails', 'contactPhones'])
            ->whereIn('contact_owner_id', $accessibleUserIds)
            ->where('business_id', auth()->user()->business_id)
            ->whereNull('moved_at')
            ->latest('updated_at')
            ->get();

        $leads = $dashboardLeads->groupBy('stage_id');
        $dashboardStats = [
            'total' => $dashboardLeads->count(),
            'active' => $dashboardLeads->whereNotIn('stage_id', [6, 7])->count(),
            'qualified' => $dashboardLeads->where('stage_id', 6)->count(),
            'unqualified' => $dashboardLeads->where('stage_id', 7)->count(),
        ];

        return view('leads.leads-dashboard', compact('leads', 'stages', 'dashboardStats'));
    }


    public function updateStage(Request $request, $leadId)
    {

        $request->validate([
            'stage_id' => 'required|exists:lead_stages,id',
            'unqualified_reason' => 'nullable|required_if:stage_id,7|string|max:2000',
        ]);

        $lead = Lead::find($leadId);

        if (!$lead) {
            return response()->json(['message' => 'Lead not found'], 404);
        }

        // Check access permission
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());
        
        if (!in_array($lead->contact_owner_id, $accessibleUserIds)) {
            return response()->json(['message' => 'You do not have permission to update this lead.'], 403);
        }

        $this->assertLeadIsOpen($lead);

        $currentStageId = (int) $lead->stage_id;
        $lead->stage_id = $request->stage_id;
        $lead->status = in_array((int) $request->stage_id, [6, 7], true)
            ? 'completed'
            : 'active';
        $lead->unqualified_reason = (int) $request->stage_id === 7 ? $request->unqualified_reason : null;
        $lead->completed_at = in_array((int) $request->stage_id, [6, 7], true) ? now() : null;
        $lead->save();
        $this->notifyTerminalLeadStatus($lead, $currentStageId);

        return response()->json([
            'message' => in_array((int) $request->stage_id, [6, 7], true)
                ? 'Lead completed successfully'
                : 'Lead status updated successfully',
            'completed' => in_array((int) $request->stage_id, [6, 7], true),
            'stage_id' => (int) $lead->stage_id,
            'stage_name' => LeadStage::find($lead->stage_id)?->name,
            'record_status' => $lead->status,
            'action' => (int) $request->stage_id === 6 ? 'convert' : (
                (int) $request->stage_id === 7 ? 'close' : null
            ),
            'conversion_url' => (int) $request->stage_id === 6
                ? route('leads.conversion-review', $lead->id) : null,
        ]);
    }

    private function notifyTerminalLeadStatus(Lead $lead, int $previousStageId): void
    {
        $stageId = (int) $lead->stage_id;
        if (!in_array($stageId, [6, 7], true) || $stageId === $previousStageId) {
            return;
        }

        $status = $stageId === 6 ? 'Qualified' : 'Unqualified';
        $owner = User::find($lead->contact_owner_id);
        $recipients = User::where('business_id', $lead->business_id)
            ->where(function ($query) use ($owner) {
                $query->where('is_admin', 1);
                if ($owner?->reporting_manager_id) {
                    $query->orWhere('id', $owner->reporting_manager_id);
                }
            })
            ->get()
            ->unique('id');

        if ($recipients->isEmpty()) {
            return;
        }

        app(CrmNotificationService::class)->send(
            $recipients,
            $stageId === 6 ? 'lead_qualified' : 'lead_unqualified',
            "Lead {$status}: {$lead->topic}",
            "{$owner?->name} changed Lead “{$lead->topic}” to {$status}. It has been removed from the active Lead list.",
            route('leads.view', ['id' => $lead->id]),
            'Lead',
            $lead->id,
            $status
        );
    }

    public function create(Request $request)
    {
        $user = auth()->user();
        $businessId = $user->business_id;
        
        $languages = Language::all();
        $countries = Country::where('status', 'active')->orderBy('name')->get(['id', 'country_code', 'name']);
        $contacts = Contact::where('business_id', $businessId)
            ->orderBy('first_name')->orderBy('last_name')->get();
        $stages = LeadStage::active()->orderBy('id')->get();
        $companies = Company::all();
        $products = Product::where('business_id', $businessId)
            ->where('status', 'active')
            ->orderBy('product_name')
            ->get(['id', 'product_code', 'product_name']);
        // $users = $this->getAccessibleUsers();
        $users = User::where('business_id', $businessId)->get();

        // check if coming from a contact
        $viaContact = $request->has('id') ? 1 : 0;
        $contactId = $request->get('id');
        $ticketId = $request->query('ticketId');

        return view('leads.leads-create', compact('languages', 'countries', 'contacts', 'stages', 'companies', 'products', 'users', 'viaContact',
        'contactId', 'ticketId'));
    }

    public function store(Request $request)
    {
        // Validate that the selected owner is accessible to current user
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());

        $request->validate([
            'contact_owner' => 'required|in:' . implode(',', $accessibleUserIds),
            'topic' => 'required|string|max:255',
            'phones' => 'required|array|min:1',
            'phones.*' => 'required|string|max:50',
            'contact_methods' => 'nullable|array',
            'contact_methods.*' => ['string', Rule::in(['Phone', 'Email', 'Social Media', 'Postal Mail', 'Fax'])],
            'languages' => 'nullable|array',
            'languages.*' => 'integer|distinct|exists:languages,id',
            'social_media_types' => 'nullable|array',
            'social_media_types.*' => ['nullable', 'required_with:social_media_values.*', Rule::in(['facebook', 'twitter', 'linkedin', 'instagram', 'other'])],
            'social_media_values' => 'nullable|array',
            'social_media_values.*' => 'nullable|required_with:social_media_types.*|string|max:500',
            'interest_products' => 'nullable|array',
            'interest_products.*' => [
                'integer',
                'distinct',
                Rule::exists('products', 'id')->where(fn ($query) => $query
                    ->where('business_id', auth()->user()->business_id)
                    ->where('status', 'active')),
            ],
        ], [
            'contact_owner.required' => 'Contact Owner is required.',
            'contact_owner.in' => 'The selected Contact Owner is not available to you.',
            'phones.required' => 'Phone Number is required.',
            'phones.*.required' => 'Phone Number is required.',
            'social_media_types.*.required_with' => 'Please select a Social Media platform.',
            'social_media_values.*.required_with' => 'Please enter the Social Media URL or handle.',
        ]);

        $duplicateIds = $this->findDuplicateLeadIds($request);
        if ($duplicateIds->isNotEmpty() && ! $request->boolean('confirm_duplicate')) {
            throw ValidationException::withMessages([
                'duplicate' => 'Possible duplicate Lead(s) found: #'.$duplicateIds->join(', #').
                    '. Review those records or select Confirm duplicate creation.',
            ]);
        }

        $leadScore = $this->calculateLeadScore($request);
        $temperature = $leadScore >= 70 ? 'hot' : ($leadScore >= 40 ? 'warm' : 'cold');

        $lead = Lead::create([
            'business_id' => auth()->user()->business_id,
            'primary_contact_id' => $request->primary_contact,
            'contact_owner_id' => $request->contact_owner,
            'lead_source' => $request->lead_source,
            'topic' => $request->topic,
            'qualification' => $request->qualification,
            'first_name' => $request->first_name,
            'last_name' => $request->last_name,
            'company_id' => $request->company_id,
            'industry_id' => $request->industry_id,
            'job_title' => $request->job_title,
            'address_1' => $request->address1,
            'address_2' => $request->address2,
            'city' => $request->city,
            'province' => $request->province,
            'zip_code' => $request->zipcode,
            'country_id' => $request->country_id,
            'contact_method' =>  json_encode($request->input('contact_methods')),
            'stage_id' => $request->stage_id,
            'lead_score' => $leadScore,
            'temperature' => $temperature,
            'qualified_at' => (int) $request->stage_id === 6 ? now() : null,
            'unqualified_reason' => (int) $request->stage_id === 7 ? $request->unqualified_reason : null,
            'duplicate_of_id' => $duplicateIds->first(),
            'completed_at' => in_array((int) $request->stage_id, [6, 7], true) ? now() : null,
            'status' => in_array((int) $request->stage_id, [6, 7], true)
                ? 'completed'
                : ($request->status ?? 'active'),
        ]);
        $lead->interestProducts()->sync($request->input('interest_products', []));
        OperationsFoundationController::recordAssignment($lead, 'leads');
        if ($owner = User::find($lead->contact_owner_id)) {
            app(CrmNotificationService::class)->assignment(
                $owner, $lead, 'Lead', route('leads.view', ['id' => $lead->id])
            );
        }

        if ($request->filled('source_ticket_id')) {
            $sourceTicket = \App\Models\Ticket::where('id', $request->source_ticket_id)
                ->where('business_id', auth()->user()->business_id)->firstOrFail();
            $sourceTicket->recordMove('lead', $lead, $request->input('move_reason'));
        }

        // Only update contact_lead if method 2
        if ($request->has('via_contact') && $request->via_contact == 1 && $request->filled('contact_id')) {
            \DB::table('contact_leads')->insert([
                'contact_id' => $request->contact_id,
                'lead_id' => $lead->id,
                'status' => $request->status,
            ]);


            Contact::where('id', $request->contact_id)
                        ->update(['stage_id' => '3']);
            Contact::where('id', $request->contact_id)
                ->where('business_id', auth()->user()->business_id)
                ->first()?->recordMove('lead', $lead, $request->input('move_reason'));
        }else{

        // dd($lead);
        if ($request->primary_contact != null) {
            $contact = Contact::create([
                'business_id' => auth()->user()->business_id,
                'lead_id' => $lead->id,
                'first_name' => $request->first_name,
                'last_name' => $request->last_name,
                'job_title' => $request->job_title,
                'company_id' => $request->company_id,
                'contact_owner_id' => $request->contact_owner,
                'marketing_source_id' => $request->lead_source,
                'address_1' => $request->address1,
                'address_2' => $request->address2,
                'city' => $request->city,
                'province' => $request->province,
                'zip_code' => $request->zipcode,
                'country_id' => $request->country_id,
                'industry_id' => $request->industry_id,
                'description' => $request->about ?: null,
                'stage_id' => $request->stage_id,
                'status' => $request->status,
            ]);
        }
        
        }

        foreach ($request->input('phones', []) as $index => $phone) {
            if (!empty($phone)) { 
            ContactPhoneNum::create([
                'lead_id' => $lead->id,
                'phone_type_id' => $request->input('phone_types')[$index],
                'phone' => $phone,
            ]);
            }
        }

        // Store emails
        foreach ($request->input('emails', []) as $index => $email) {
            if (filled($email)) {
                ContactEmail::create([
                    'lead_id' => $lead->id,
                    'email_type_id' => $request->input('email_types', [])[$index] ?? null,
                    'email' => $email,
                ]);
            }
        }

        $socialMediaTypeMap = [
            'facebook' => 1,
            'twitter' => 2,
            'linkedin' => 3,
            'instagram' => 4,
            'other' => 5,
        ];

        foreach ($request->input('social_media_values', []) as $index => $social_media_value) {
            if (! filled($social_media_value)) {
                continue;
            }

            $socialMediaType = $request->input('social_media_types', [])[$index] ?? null;

            $socialMediaTypeId = $socialMediaTypeMap[$socialMediaType] ?? null;

            if ($socialMediaTypeId) {
                ContactSocialMedia::create([
                    'lead_id' => $lead->id,
                    'social_media_type_id' => $socialMediaTypeId,
                    'value' => trim((string) $social_media_value),
                ]);
            }
        }

        if (!empty($request->languages)) {
            foreach ($request->languages as $languageId) {
                ContactLanguage::create([
                    'lead_id' => $lead->id,
                    'language_id' => $languageId,
                ]);
            }    
        }


        return redirect()->route('leads')->with('success', 'Lead created successfully!');
    }

    public function show(Request $request)
    {

        $leadId = $request->query('id');
        $lead = Lead::with([
            'contactPhones',
            'contactEmails',
            'contactSocialMedia',
            'contactLanguages',
            'assignedUser',
            'interestProducts',
            'activities', 'deals', 'projects', 'surveys', 'cases',
            'conversionHistories.deal', 'conversionHistories.actor',
            'reopenHistories.actor',
        ])->where('business_id', auth()->user()->business_id)->findOrFail($leadId);

        // Check if current user can access this lead's owner
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());
        
        if (!in_array($lead->contact_owner_id, $accessibleUserIds)) {
            abort(403, 'You do not have permission to view this lead.');
        }

        $notes = Note::visibleTo(auth()->user())->where('lead_id', $leadId)->get();
        // Keep the profile timeline scoped to this lead while including activities
        // that only have a due/end date (or no scheduled date at all).
        $activities = $lead->activities()
            ->with('owner')
            ->orderByRaw('COALESCE(start_date, due_date, end_date, created_at) DESC')
            ->orderByDesc('created_at')
            ->get();
        $activityMoment = fn ($activity) => $activity->start_date
            ? Carbon::parse($activity->start_date.' '.($activity->start_time ?: '00:00:00'))
            : $activity->created_at;
        $lastInteraction = $activities->filter(fn ($activity) => $activityMoment($activity)->lte(now()))
            ->sortByDesc($activityMoment)->first();
        $nextInteraction = $activities->filter(fn ($activity) =>
            $activityMoment($activity)->gt(now()) &&
            !in_array($activity->lifecycle_status, ['completed', 'cancelled'], true)
        )->sortBy($activityMoment)->first();
        $invitedMeetings = $activities->filter(fn ($activity) =>
            (int) $activity->activity_type_id === 2 || filled($activity->meeting_type) || filled($activity->meeting_integration_id)
        );

        $won = WonLost::where('lead_id', $leadId)
            ->where('status', 'WON')
            ->get();
        $lost = WonLost::where('lead_id', $leadId)
            ->where('status', 'LOST')
            ->get();
        $stages = LeadStage::active()->orderBy('id')->get();
        $deals = $lead->deals()->get();
        $projectIds = $lead->projects->pluck('id')->merge(
            Project::where('business_id', $lead->business_id)->whereIn('deal_id', $deals->pluck('id'))->pluck('id')
        )->unique();
        $projects = Project::whereIn('id', $projectIds)->get();
        $tradeDocuments = TradeDocument::where('business_id', $lead->business_id)
            ->whereIn('deal_id', $deals->pluck('id'))->with('deal')->latest()->get();
        $cases = $lead->cases()->where('business_id', $lead->business_id)->latest()->get();
        $surveys = $lead->surveys()->where('surveys.business_id', $lead->business_id)
            ->orderByDesc('surveys.created_at')->get();
        $conversionHistories = $lead->conversionHistories()->with(['deal', 'actor'])->latest()->get();
        $leadIsCompleted = $this->leadIsCompleted($lead);
        $canReopen = $leadIsCompleted && $this->canReopenLead($lead);
        $profileLanguageOptions = Language::orderBy('name')->get(['id', 'name']);
        $profileCountryOptions = Country::where('status', 'active')->orderBy('name')->get(['id', 'name']);
        $profileCompanyOptions = Company::orderBy('name')->get(['id', 'name']);
        $profileProductOptions = Product::where('business_id', $lead->business_id)
            ->where(function ($query) {
                $query->whereNull('status')->orWhere('status', 'active');
            })
            ->orderBy('product_name')
            ->get(['id', 'product_name', 'product_code', 'price', 'status']);

        return view('leads.leads-view', compact(
            'lead', 'notes', 'activities', 'lastInteraction', 'nextInteraction', 'invitedMeetings',
            'won', 'lost', 'stages', 'deals', 'projects', 'tradeDocuments', 'cases', 'surveys',
            'conversionHistories', 'leadIsCompleted', 'canReopen', 'profileLanguageOptions',
            'profileCountryOptions', 'profileCompanyOptions', 'profileProductOptions'
        ));
    }

    public function addProduct(Request $request, Lead $lead)
    {
        $this->authorizeLeadProfileUpdate($lead);

        $validated = $request->validate([
            'product_id' => [
                'required',
                'integer',
                Rule::exists('products', 'id')->where(fn ($query) => $query
                    ->where('business_id', $lead->business_id)
                    ->where(function ($statusQuery) {
                        $statusQuery->whereNull('status')->orWhere('status', 'active');
                    })),
            ],
        ]);

        $lead->interestProducts()->syncWithoutDetaching([$validated['product_id']]);

        return back()->with('success', 'Product added to this Lead.');
    }

    public function removeProduct(Lead $lead, Product $product)
    {
        $this->authorizeLeadProfileUpdate($lead);
        abort_unless((int) $product->business_id === (int) $lead->business_id, 404);

        $lead->interestProducts()->detach($product->id);

        return back()->with('success', 'Product removed from this Lead.');
    }

    private function authorizeLeadProfileUpdate(Lead $lead): void
    {
        abort_unless((int) $lead->business_id === (int) auth()->user()->business_id, 404);

        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());
        abort_unless(in_array((int) $lead->contact_owner_id, array_map('intval', $accessibleUserIds), true), 403);
    }

    public function edit(Request $request)
    {
        $leadId = $request->query('id');

        $lead = Lead::with(['contactPhones', 'contactEmails', 'contactSocialMedia', 'contactLanguages', 'interestProducts'])->findOrFail($leadId);

        // Check access permission
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());
        
        if (!in_array($lead->contact_owner_id, $accessibleUserIds)) {
            abort(403, 'You do not have permission to edit this lead.');
        }

        $this->assertLeadIsOpen($lead);

        $languages = Language::all();
        $countries = Country::where('status', 'active')->orderBy('name')->get(['id', 'country_code', 'name']);
        $contacts = Contact::where('business_id', auth()->user()->business_id)
            ->orderBy('first_name')->orderBy('last_name')->get();
        $stages = LeadStage::active()->orderBy('id')->get();
        $companies = Company::all();
        $products = Product::where('business_id', auth()->user()->business_id)
            ->where('status', 'active')
            ->orderBy('product_name')
            ->get(['id', 'product_code', 'product_name']);
        $users = $this->getAccessibleUsers();

        return view('leads.leads-edit', compact('lead', 'languages', 'countries', 'contacts', 'stages', 'companies', 'products', 'users'));
    }



    public function update(Request $request, $id)
    {
        $lead = Lead::findOrFail($id);
        $previousOwnerId = (int) $lead->contact_owner_id;

        // Check access permission
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());
        
        if (!in_array($lead->contact_owner_id, $accessibleUserIds)) {
            abort(403, 'You do not have permission to update this lead.');
        }

        $this->assertLeadIsOpen($lead);

        // Validate that the new owner is accessible
        $request->validate([
            'contact_owner' => 'required|in:' . implode(',', $accessibleUserIds),
            'topic' => 'required|string|max:255',
            'phones' => 'required|array|min:1',
            'phones.*' => 'required|string|max:50',
            'contact_methods' => 'nullable|array',
            'contact_methods.*' => ['string', Rule::in(['Phone', 'Email', 'Social Media', 'Postal Mail', 'Fax'])],
            'languages' => 'nullable|array',
            'languages.*' => 'integer|distinct|exists:languages,id',
            'social_media_types' => 'nullable|array',
            'social_media_types.*' => ['nullable', 'required_with:social_media_values.*', Rule::in(['facebook', 'twitter', 'linkedin', 'instagram', 'other'])],
            'social_media_values' => 'nullable|array',
            'social_media_values.*' => 'nullable|required_with:social_media_types.*|string|max:500',
            'interest_products' => 'nullable|array',
            'interest_products.*' => [
                'integer',
                'distinct',
                Rule::exists('products', 'id')->where(fn ($query) => $query
                    ->where('business_id', auth()->user()->business_id)
                    ->where('status', 'active')),
            ],
        ], [
            'contact_owner.required' => 'Contact Owner is required.',
            'contact_owner.in' => 'The selected Contact Owner is not available to you.',
            'phones.required' => 'Phone Number is required.',
            'phones.*.required' => 'Phone Number is required.',
            'social_media_types.*.required_with' => 'Please select a Social Media platform.',
            'social_media_values.*.required_with' => 'Please enter the Social Media URL or handle.',
        ]);

        // Update lead data
        $lead->update([
            'business_id' => auth()->user()->business_id,
            'primary_contact_id' => $request->primary_contact,
            'contact_owner_id' => $request->contact_owner,
            'lead_source' => $request->lead_source,
            'topic' => $request->topic,
            'qualification' => $request->qualification,
            'first_name' => $request->first_name,
            'last_name' => $request->last_name,
            'company_id' => $request->company_id,
            'industry_id' => $request->industry_id,
            'job_title' => $request->job_title,
            'address_1' => $request->address1,
            'address_2' => $request->address2,
            'city' => $request->city,
            'province' => $request->province,
            'zip_code' => $request->zipcode,
            'country_id' => $request->country_id,
            'contact_method' =>  json_encode($request->input('contact_methods')),
            'stage_id' => $request->stage_id,
            'unqualified_reason' => (int) $request->stage_id === 7 ? $request->unqualified_reason : null,
            'completed_at' => in_array((int) $request->stage_id, [6, 7], true) ? ($lead->completed_at ?: now()) : null,
            'status' => in_array((int) $request->stage_id, [6, 7], true)
                ? 'completed'
                : ($request->status ?? 'active'),
        ]);
        $lead->interestProducts()->sync($request->input('interest_products', []));
        if ($previousOwnerId !== (int) $lead->contact_owner_id
            && ($owner = User::find($lead->contact_owner_id))) {
            app(CrmNotificationService::class)->assignment(
                $owner, $lead, 'Lead', route('leads.view', ['id' => $lead->id])
            );
        }

        if ($request->primary_contact) {
            $contact = Contact::updateOrCreate(
                ['lead_id' => $lead->id],
                [
                    'business_id' => auth()->user()->business_id,
                    'first_name' => $request->first_name,
                    'last_name' => $request->last_name,
                    'job_title' => $request->job_title,
                    'company_id' => $request->company_id,
                    'contact_owner_id' => $request->contact_owner,
                    'marketing_source_id' => $request->lead_source,
                    'address_1' => $request->address1,
                    'address_2' => $request->address2,
                    'city' => $request->city,
                    'province' => $request->province,
                    'zip_code' => $request->zipcode,
                    'country_id' => $request->country_id,
                    'industry_id' => $request->industry_id,
                    'description' => $request->about ?: null,
                    'stage_id' => $request->stage_id,
                    'status' => $request->status,
                ]
            );
        }

        ContactPhoneNum::where('lead_id', $id)->delete();
        if (!empty($request->phones)) {
            foreach ($request->phones as $index => $phone) {
                ContactPhoneNum::create([
                    'lead_id' => $id,
                    'phone_type_id' => $request->phone_types[$index] ?? null,
                    'phone' => $phone,
                ]);
            }
        }

        ContactEmail::where('lead_id', $id)->delete();
        foreach ($request->input('emails', []) as $index => $email) {
            if (filled($email)) {
                ContactEmail::create([
                    'lead_id' => $id,
                    'email_type_id' => $request->input('email_types', [])[$index] ?? null,
                    'email' => $email,
                ]);
            }
        }

        $socialMediaTypeMap = [
            'facebook' => 1,
            'twitter' => 2,
            'linkedin' => 3,
            'instagram' => 4,
            'other' => 5,
        ];

        ContactSocialMedia::where('lead_id', $id)->delete();
        foreach ($request->input('social_media_values', []) as $index => $social_media_value) {
                if (! filled($social_media_value)) {
                    continue;
                }

                $socialMediaType = $request->input('social_media_types', [])[$index] ?? null;
                $socialMediaTypeId = $socialMediaTypeMap[$socialMediaType] ?? null;

                if ($socialMediaTypeId) {
                    ContactSocialMedia::create([
                        'lead_id' => $id,
                        'social_media_type_id' => $socialMediaTypeId,
                        'value' => trim((string) $social_media_value),
                    ]);
                }
        }

        ContactLanguage::where('lead_id', $id)->delete();
        foreach ($request->input('languages', []) as $languageId) {
            ContactLanguage::create([
                'lead_id' => $id,
                'language_id' => $languageId,
            ]);
        }

        return redirect()->route('leads')->with('success', 'Lead updated successfully!');
    }

    public function updateProfileField(Request $request, int $id)
    {
        $lead = Lead::where('business_id', auth()->user()->business_id)->findOrFail($id);
        abort_unless(in_array($lead->contact_owner_id, $this->getAccessibleUserIds(auth()->id())), 403);
        $this->assertLeadIsOpen($lead);

        $allowedFields = [
            'first_name', 'emails', 'phones', 'job_title', 'company_id', 'languages',
            'lead_source', 'qualification', 'interest_products', 'address1', 'city',
            'country_id', 'zipcode', 'contact_methods',
        ];
        $field = $request->validate(['field' => ['required', Rule::in($allowedFields)]])['field'];

        $rules = match ($field) {
            'first_name' => ['value' => ['required', 'string', 'max:255'], 'secondary_value' => ['nullable', 'string', 'max:255']],
            'emails' => ['value' => ['required', 'email', 'max:255']],
            'phones' => ['value' => ['required', 'string', 'max:50']],
            'job_title', 'qualification', 'address1', 'city', 'zipcode' => [
                'value' => ['required', 'string', 'max:500'],
                'secondary_value' => ['nullable', 'string', 'max:500'],
            ],
            'company_id' => ['value' => ['required', 'integer', 'exists:companies,id']],
            'country_id' => ['value' => ['required', 'integer', Rule::exists('countries', 'id')->where('status', 'active')]],
            'lead_source' => ['value' => ['required', 'integer', Rule::in([2, 3, 4, 5, 6, 7])]],
            'languages' => ['value' => ['required', 'array', 'min:1'], 'value.*' => ['integer', 'distinct', 'exists:languages,id']],
            'interest_products' => [
                'value' => ['required', 'array', 'min:1'],
                'value.*' => ['integer', 'distinct', Rule::exists('products', 'id')->where(fn ($query) => $query
                    ->where('business_id', auth()->user()->business_id)->where('status', 'active'))],
            ],
            'contact_methods' => [
                'value' => ['required', 'array', 'min:1'],
                'value.*' => ['string', 'distinct', Rule::in(['Phone', 'Email', 'Social Media', 'Postal Mail', 'Fax'])],
            ],
        };
        $validated = $request->validate($rules);
        $value = $validated['value'];

        match ($field) {
            'first_name' => $lead->update(['first_name' => $value, 'last_name' => $validated['secondary_value'] ?? null]),
            'emails' => ContactEmail::updateOrCreate(
                ['id' => $lead->contactEmails()->value('id')],
                ['lead_id' => $lead->id, 'email_type_id' => $lead->contactEmails()->value('email_type_id') ?: 1, 'email' => $value]
            ),
            'phones' => ContactPhoneNum::updateOrCreate(
                ['id' => $lead->contactPhones()->value('id')],
                ['lead_id' => $lead->id, 'phone_type_id' => $lead->contactPhones()->value('phone_type_id') ?: 1, 'phone' => $value]
            ),
            'job_title' => $lead->update(['job_title' => $value]),
            'company_id' => $lead->update(['company_id' => $value]),
            'languages' => $this->syncProfileLanguages($lead, $value),
            'lead_source' => $lead->update(['lead_source' => $value]),
            'qualification' => $lead->update(['qualification' => $value]),
            'interest_products' => $lead->interestProducts()->sync($value),
            'address1' => $lead->update(['address_1' => $value, 'address_2' => $validated['secondary_value'] ?? null]),
            'city' => $lead->update(['city' => $value, 'province' => $validated['secondary_value'] ?? null]),
            'country_id' => $lead->update(['country_id' => $value]),
            'zipcode' => $lead->update(['zip_code' => $value]),
            'contact_methods' => $lead->update(['contact_method' => $value]),
        };

        $lead->refresh()->load(['contactEmails', 'contactPhones', 'contactLanguages.language', 'interestProducts', 'company', 'country']);

        $displayValue = match ($field) {
            'first_name' => trim($lead->first_name.' '.$lead->last_name),
            'emails' => $lead->contactEmails->first()?->email,
            'phones' => $lead->contactPhones->first()?->phone,
            'company_id' => $lead->company?->name,
            'languages' => $lead->contactLanguages->pluck('language.name')->filter()->join(', '),
            'lead_source' => [2 => 'Social Media', 3 => 'Referral', 4 => 'Email Campaign', 5 => 'Cold Call', 6 => 'Trade Show', 7 => 'Website'][(int) $lead->lead_source] ?? 'Not selected',
            'interest_products' => $lead->interestProducts->pluck('product_name')->filter()->join(', '),
            'address1' => collect([$lead->address_1, $lead->address_2])->filter()->join(', '),
            'city' => collect([$lead->city, $lead->province])->filter()->join(', '),
            'country_id' => $lead->country?->name,
            'zipcode' => $lead->zip_code,
            'contact_methods' => collect($lead->contact_method)->filter()->join(', '),
            default => $lead->{$field},
        };

        return response()->json(['message' => 'Lead field updated successfully.', 'display_value' => $displayValue]);
    }

    private function syncProfileLanguages(Lead $lead, array $languageIds): bool
    {
        ContactLanguage::where('lead_id', $lead->id)->delete();
        foreach ($languageIds as $languageId) {
            ContactLanguage::create(['lead_id' => $lead->id, 'language_id' => $languageId]);
        }

        return true;
    }

    public function conversionReview(int $id)
    {
        $lead = Lead::with(['contactEmails', 'contactPhones', 'conversionHistories.deal'])
            ->where('business_id', auth()->user()->business_id)->findOrFail($id);
        abort_unless(in_array($lead->contact_owner_id, $this->getAccessibleUserIds(auth()->id())), 403);
        abort_unless((int) $lead->stage_id === 6, 422, 'Only Qualified Leads can be converted to Deals.');

        $duplicateDeals = Deal::where('business_id', $lead->business_id)
            ->where(function ($query) use ($lead) {
                $query->where('lead_id', $lead->id);
                if ($lead->primary_contact_id) $query->orWhere('contact_id', $lead->primary_contact_id);
                if ($lead->company_id) $query->orWhere('company_id', $lead->company_id);
                if ($lead->topic) $query->orWhere('name', $lead->topic);
            })->get();

        return view('leads.conversion-review', compact('lead', 'duplicateDeals'));
    }

    private function findDuplicateLeadIds(Request $request)
    {
        $businessId = auth()->user()->business_id;
        $emails = collect($request->input('emails', []))->filter()->map(fn ($email) => strtolower(trim($email)));
        $phones = collect($request->input('phones', []))->filter()->map(fn ($phone) => preg_replace('/\D+/', '', $phone));
        $matchedIds = collect();

        if ($emails->isNotEmpty()) {
            $matchedIds = $matchedIds->merge(ContactEmail::whereIn(\DB::raw('LOWER(email)'), $emails)->pluck('lead_id'));
        }
        if ($phones->isNotEmpty()) {
            $matchedIds = $matchedIds->merge(ContactPhoneNum::whereIn('phone', $request->input('phones', []))->pluck('lead_id'));
        }

        $nameMatches = Lead::where('business_id', $businessId)
            ->where('first_name', $request->first_name)
            ->where('last_name', $request->last_name);
        if ($request->company_id) $nameMatches->where('company_id', $request->company_id);

        return $matchedIds->merge($nameMatches->pluck('id'))->filter()->unique()->values();
    }

    private function calculateLeadScore(Request $request): int
    {
        $score = 20; // A mandatory topic establishes the initial business need.
        $score += $request->filled('company_id') ? 20 : 0;
        $score += $request->filled('primary_contact') ? 20 : 0;
        $score += collect($request->input('emails', []))->filter()->isNotEmpty() ? 20 : 0;
        $score += collect($request->input('phones', []))->filter()->isNotEmpty() ? 20 : 0;

        return min(100, $score);
    }


    public function destroy($id)
    {
        // Find the lead by ID
        $lead = Lead::findOrFail($id);

        // Check access permission
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());
        
        if (!in_array($lead->contact_owner_id, $accessibleUserIds)) {
            abort(403, 'You do not have permission to delete this lead.');
        }

        $this->assertLeadIsOpen($lead);

        if ($lead->primary_contact_id !== null) {
            $contact = Contact::where('lead_id', $lead->id)->firstOrFail();
            $contact->delete();
        }

        $lead->contactPhones()->delete();
        $lead->contactEmails()->delete();
        $lead->contactSocialMedia()->delete();
        $lead->contactLanguages()->delete();


        $lead->delete();

        return redirect()->route('leads')->with('success', 'Lead and associated Contact deleted successfully!');
    }

    public function reopen(Request $request, Lead $lead)
    {
        $validated = $request->validate([
            'reason' => ['required', 'string', 'min:10', 'max:2000'],
        ]);

        abort_unless((int) $lead->business_id === (int) auth()->user()->business_id, 403);
        abort_unless($this->leadIsCompleted($lead), 422, 'Only completed Leads can be reopened.');
        abort_unless($this->canReopenLead($lead), 403, 'Management permission is required to reopen a completed Lead.');

        $fromStageId = (int) $lead->stage_id;
        $toStageId = 5; // Contacted

        \DB::transaction(function () use ($lead, $validated, $fromStageId, $toStageId) {
            $lead->update([
                'stage_id' => $toStageId,
                'status' => 'active',
                'completed_at' => null,
                'qualified_at' => null,
                'unqualified_reason' => null,
                'reopened_at' => now(),
                'reopen_count' => (int) $lead->reopen_count + 1,
            ]);

            LeadStageStatus::where('lead_id', $lead->id)->whereIn('stage_id', [6, 7])->delete();
            LeadStageStatus::updateOrCreate(
                ['lead_id' => $lead->id, 'stage_id' => $toStageId],
                ['stage_status' => 1]
            );
            $lead->reopenHistories()->create([
                'business_id' => $lead->business_id,
                'from_stage_id' => $fromStageId,
                'to_stage_id' => $toStageId,
                'reopened_by' => auth()->id(),
                'reason' => $validated['reason'],
            ]);
        });

        return redirect()->route('leads.view', ['id' => $lead->id])
            ->with('success', 'Lead reopened at Contacted.');
    }

    private function leadIsCompleted(Lead $lead): bool
    {
        return in_array((int) $lead->stage_id, [6, 7], true) || $lead->status === 'completed';
    }

    private function canReopenLead(Lead $lead): bool
    {
        $user = auth()->user();
        $owner = User::find($lead->contact_owner_id);

        return (bool) $user->is_admin
            || (int) $owner?->reporting_manager_id === (int) $user->id
            || $user->can('reopen_completed_leads');
    }

    private function assertLeadIsOpen(Lead $lead): void
    {
        abort_if($this->leadIsCompleted($lead), 423, 'Completed Leads are read-only. Reopen the Lead first.');
    }
}
