<?php

namespace App\Services;

use App\Models\Lead;
use App\Models\LeadDuplicate;
use App\Models\LeadSourceConnection;
use App\Models\WebhookLog;
use Illuminate\Support\Facades\Log;

/**
 * Lead Ingestion Service
 *
 * Duplicate detection behaviour (by design):
 *   - Exact source+source_id match   → skipped entirely; returns null; no DB write.
 *   - Email OR phone matches existing → NO new lead created; a lead_duplicates record
 *     is inserted (original_lead_id = existing lead, duplicate_lead_id = null,
 *     attempted_data = raw payload); the original lead is touched; returns null.
 *   - Unique contact                  → new Lead row; is_duplicate=false; returns Lead.
 */
class LeadIngestionService
{
    public function __construct(protected LeadDuplicateDetector $duplicateDetector) {}

    public function ingestLead(array $data, LeadSourceConnection $connection, WebhookLog $log): ?Lead
    {
        $email = isset($data['email']) ? strtolower(trim($data['email'])) : null;
        $phone = $data['phone'] ?? null;

        if (! empty($data['source_id'])) {
            $existingBySourceId = Lead::where('tenant_id', $connection->tenant_id)
                ->where('source', $connection->source)
                ->where('source_id', $data['source_id'])
                ->first();

            if ($existingBySourceId) {
                Log::debug('[LeadIngestion] Skipped: exact source+source_id duplicate', [
                    'source_id'   => $data['source_id'],
                    'source'      => $connection->source,
                    'existing_id' => $existingBySourceId->id,
                ]);
                return null;
            }
        }

        $original = $this->duplicateDetector->findExisting(
            $connection->tenant_id,
            $email,
            $phone,
        );

        if ($original) {
            $matchField = $this->duplicateDetector->matchField(
                $original->email,
                $original->phone,
                $email,
                $phone
            );

            LeadDuplicate::create([
                'tenant_id'         => $connection->tenant_id,
                'original_lead_id'  => $original->id,
                'duplicate_lead_id' => null,
                'match_field'       => $matchField,
                'attempted_data'    => [
                    'source'       => $connection->source,
                    'first_name'   => $data['first_name'] ?? null,
                    'last_name'    => $data['last_name'] ?? null,
                    'email'        => $email,
                    'phone'        => $phone,
                    'source_id'    => $data['source_id'] ?? null,
                    'custom_fields' => $data['custom_fields'] ?? null,
                ],
            ]);

            $original->touch();

            Log::info('[LeadIngestion] Duplicate detected — no new lead created; lead_duplicates record stored', [
                'original_lead_id' => $original->id,
                'match_field'      => $matchField,
                'source'           => $connection->source,
            ]);

            return null;
        }

        $lead = Lead::create([
            'tenant_id'            => $connection->tenant_id,
            'source'               => $connection->source,
            'source_id'            => $data['source_id'] ?? null,
            'source_connection_id' => $connection->id,
            'first_name'           => $data['first_name'] ?? null,
            'last_name'            => $data['last_name'] ?? null,
            'email'                => $email,
            'phone'                => $phone,
            'status'               => 'new',
            'is_duplicate'         => false,
            'raw_data'             => $data['raw_data'] ?? null,
            'custom_fields'        => $data['custom_fields'] ?? null,
        ]);

        Log::info('[LeadIngestion] New lead created', [
            'lead_id' => $lead->id,
            'source'  => $connection->source,
        ]);

        return $lead;
    }

    /**
     * Ingest a lead from a public source that has no LeadSourceConnection /
     * WebhookLog — currently the embeddable lead-capture widget
     * (PublicWidgetController::submit()).
     *
     * That POST runs unauthenticated with no bound tenant, so bind the
     * widget's trusted tenant_id here before writing: otherwise the
     * BelongsToTenant scope and the Lead observers resolve the wrong tenant
     * (or fail closed). De-duplicates on email/phone like ingestLead();
     * returns the new or existing Lead.
     */
    public function ingest(int $tenantId, array $data): ?Lead
    {
        $current = app()->bound('current_tenant') ? app('current_tenant') : null;
        if (! $current || $current->id !== $tenantId) {
            $tenant = \App\Models\Tenant::withoutGlobalScope('tenant')->find($tenantId);
            if ($tenant) {
                app()->instance('current_tenant', $tenant);
            }
        }

        $email = isset($data['email']) ? strtolower(trim((string) $data['email'])) : null;
        $phone = $data['phone'] ?? null;

        if ($existing = $this->duplicateDetector->findExisting($tenantId, $email, $phone)) {
            $existing->touch();

            return $existing;
        }

        return Lead::create([
            'tenant_id'         => $tenantId,
            'source'            => $data['source'] ?? 'web_form',
            'source_id'         => $data['source_id'] ?? null,
            'first_name'        => $data['first_name'] ?? null,
            'last_name'         => $data['last_name'] ?? null,
            'email'             => $email,
            'phone'             => $phone,
            'company'           => $data['company'] ?? null,
            'status'            => 'new',
            'pipeline_id'       => $data['pipeline_id'] ?? null,
            'pipeline_stage_id' => $data['pipeline_stage_id'] ?? null,
            'raw_data'          => $data['raw_data'] ?? null,
            'utm_source'        => $data['utm_source'] ?? null,
            'utm_medium'        => $data['utm_medium'] ?? null,
            'utm_campaign'      => $data['utm_campaign'] ?? null,
            'utm_content'       => $data['utm_content'] ?? null,
            'utm_term'          => $data['utm_term'] ?? null,
            'landing_page'      => $data['landing_page'] ?? null,
            'referrer_url'      => $data['referrer_url'] ?? null,
        ]);
    }

    public function createOrSkipDuplicate(array $data, LeadSourceConnection $connection, WebhookLog $log): ?Lead
    {
        return $this->ingestLead($data, $connection, $log);
    }

    public function createLead(array $data, LeadSourceConnection $connection, WebhookLog $log): Lead
    {
        $lead = Lead::create([
            'tenant_id'            => $connection->tenant_id,
            'source'               => $connection->source,
            'source_id'            => $data['source_id'] ?? null,
            'source_connection_id' => $connection->id,
            'first_name'           => $data['first_name'] ?? null,
            'last_name'            => $data['last_name'] ?? null,
            'email'                => isset($data['email']) ? strtolower(trim($data['email'])) : null,
            'phone'                => $data['phone'] ?? null,
            'status'               => 'new',
            'raw_data'             => $data['raw_data'] ?? null,
            'custom_fields'        => $data['custom_fields'] ?? null,
        ]);

        $this->duplicateDetector->detectAndLink($lead);

        return $lead;
    }
}
