<?php

namespace App\Services;

use App\Models\Campaign;
use App\Models\CampaignEvent;
use App\Models\Contact;
use App\Models\ContactActivity;
use App\Jobs\ProcessAutomationNodeJob;
use Illuminate\Support\Facades\Log;

class AutomationEngine
{
    public static function check(ContactActivity $activity): void
    {
        $contact = $activity->contact;
        if (!$contact) {
            return;
        }

        // Only process active automations
        $automations = Campaign::where('type', 'automation')
            ->where('status', 'active')
            ->get();

        foreach ($automations as $automation) {
            $settings = $automation->settings;
            $triggerConfig = $settings['trigger'] ?? [];

            // Normalize triggers for multiple trigger support & backward compatibility
            $logicalOperator = $triggerConfig['logical_operator'] ?? 'OR';
            $triggers = $triggerConfig['triggers'] ?? [];
            if (empty($triggers) && isset($triggerConfig['type'])) {
                $triggers = [$triggerConfig];
            }

            $shouldEnroll = false;

            if (!empty($triggers)) {
                if ($logicalOperator === 'AND') {
                    // ALL triggers must be satisfied, and the current activity MUST be the catalyst for at least one of them
                    $allSatisfied = true;
                    $anyEventMatched = false;

                    foreach ($triggers as $t) {
                        if (self::isEventMatch($t, $activity)) {
                            $anyEventMatched = true;
                        }

                        if (!self::isTriggerSatisfied($t, $contact, $activity)) {
                            $allSatisfied = false;
                            break;
                        }
                    }

                    if ($allSatisfied && $anyEventMatched) {
                        $shouldEnroll = true;
                    }
                } else {
                    // OR operator: any trigger matches the current activity event and is satisfied
                    foreach ($triggers as $t) {
                        if (self::isEventMatch($t, $activity) && self::isTriggerSatisfied($t, $contact, $activity)) {
                            $shouldEnroll = true;
                            break;
                        }
                    }
                }
            }

            if ($shouldEnroll) {
                self::enroll($automation, $contact);
            }
        }
    }

    private static function isEventMatch(array $trigger, ContactActivity $activity): bool
    {
        $tType = $trigger['type'] ?? '';

        switch ($tType) {
            case 'new_user_signup':
            case 'contact_created':
                return $activity->type === 'created';
            case 'contact_updated':
                return $activity->type === 'updated';
            case 'subscribes_to_list':
                return $activity->type === 'list_added';
            case 'unsubscribes_from_list':
                return $activity->type === 'list_removed';
            case 'tag_applied':
                return $activity->type === 'tag_added';
            case 'tag_removed':
                return $activity->type === 'tag_removed';
            case 'email_opened':
                return $activity->type === 'email_opened';
            case 'email_clicked':
                return $activity->type === 'email_clicked';
            case 'unsubscribed':
                return $activity->type === 'unsubscribed';
            case 'birthday':
                return $activity->type === 'birthday';
            case 'incoming_webhook':
                if ($activity->type !== 'webhook_received' && $activity->type !== 'incoming_webhook') {
                    return false;
                }
                $targetWebhookId = $trigger['webhook_id'] ?? null;
                if (!$targetWebhookId || $targetWebhookId === 'all') {
                    return true;
                }
                if (preg_match('/\[id:(\d+)\]/', $activity->description, $matches)) {
                    return (int)$matches[1] === (int)$targetWebhookId;
                }
                return true;
            default:
                return false;
        }
    }

    public static function isTriggerSatisfied(array $trigger, Contact $contact, ContactActivity $activity): bool
    {
        $type = $trigger['type'] ?? '';

        switch ($type) {
            case 'new_user_signup':
            case 'contact_created':
                return $activity->type === 'created';
            case 'contact_updated':
                return $activity->type === 'updated';
            case 'subscribes_to_list':
                $listId = $trigger['list_id'] ?? null;
                if ($listId === null) {
                    return true;
                }
                return $contact->lists()->where('lists.id', (int)$listId)->exists();
            case 'unsubscribes_from_list':
                return true;
            case 'tag_applied':
                $tagId = $trigger['tag_id'] ?? null;
                if ($tagId === null) {
                    return true;
                }
                return $contact->tags()->where('tags.id', (int)$tagId)->exists();
            case 'tag_removed':
                return true;
            case 'email_opened':
                $campaignId = $trigger['campaign_id'] ?? null;
                if (!$campaignId) return false;
                return \App\Models\CampaignEvent::where('contact_id', $contact->id)
                    ->where('campaign_id', $campaignId)
                    ->where('event_type', 'open')
                    ->exists();
            case 'email_clicked':
                $campaignId = $trigger['campaign_id'] ?? null;
                if (!$campaignId) return false;
                return \App\Models\CampaignEvent::where('contact_id', $contact->id)
                    ->where('campaign_id', $campaignId)
                    ->where('event_type', 'click')
                    ->exists();
            case 'unsubscribed':
                return $contact->status === 'unsubscribed';
            case 'birthday':
                if (!$contact->date_of_birth) return false;
                try {
                    $bday = is_string($contact->date_of_birth) ? new \DateTime($contact->date_of_birth) : $contact->date_of_birth;
                    return $bday->format('m-d') === now()->format('m-d');
                } catch (\Throwable $e) {
                    return false;
                }
            case 'incoming_webhook':
                $targetWebhookId = $trigger['webhook_id'] ?? null;
                $query = \App\Models\WebhookLog::where('contact_id', $contact->id)->where('status', 'success');
                if ($targetWebhookId && $targetWebhookId !== 'all') {
                    $query->where('webhook_id', (int)$targetWebhookId);
                }
                return $query->exists();
            default:
                return false;
        }
    }

    public static function enroll(Campaign $automation, Contact $contact, string $startNodeId = null): void
    {
        // Prevent double enrollment
        $hasEnrolled = CampaignEvent::where('campaign_id', $automation->id)
            ->where('contact_id', $contact->id)
            ->where('event_type', 'enrolled')
            ->exists();

        if ($hasEnrolled) {
            return;
        }

        $settings = $automation->settings;
        $nodes = $settings['nodes'] ?? [];
        $edges = $settings['edges'] ?? [];

        // Find trigger node or use startNodeId
        if (!$startNodeId) {
            $triggerNode = collect($nodes)->first(fn($n) => $n['type'] === 'trigger');
            $startNodeId = $triggerNode ? $triggerNode['id'] : 'n_trigger';
        }

        // Record enrollment event
        CampaignEvent::create([
            'campaign_id' => $automation->id,
            'contact_id'  => $contact->id,
            'event_type'  => 'enrolled',
            'node_id'     => $startNodeId,
            'reason'      => 'Contact enrolled in automation.',
        ]);

        $contact->logActivity('automation_enrolled', "Enrolled in automation: \"{$automation->title}\"");
        $automation->increment('recipients_count');

        // Find all downstream edges connected directly to trigger
        $nextEdges = collect($edges)->filter(fn($e) => $e['source'] === $startNodeId);

        foreach ($nextEdges as $edge) {
            ProcessAutomationNodeJob::dispatch($automation->id, $contact->id, $edge['target']);
        }
    }

    public static function complete(Campaign $automation, Contact $contact): void
    {
        $hasCompleted = CampaignEvent::where('campaign_id', $automation->id)
            ->where('contact_id', $contact->id)
            ->where('event_type', 'completed')
            ->exists();

        if ($hasCompleted) {
            return;
        }

        CampaignEvent::create([
            'campaign_id' => $automation->id,
            'contact_id'  => $contact->id,
            'event_type'  => 'completed',
        ]);

        $contact->logActivity('automation_completed', "Completed automation: \"{$automation->title}\"");
    }
}
