<?php
require_once __DIR__ . '/../Core.php';
require_once __DIR__ . '/MailConversation.php';
require_once __DIR__ . '/MailLabel.php';
require_once __DIR__ . '/Campaign.php';
require_once __DIR__ . '/QueueJob.php';
require_once __DIR__ . '/Setting.php';

class AutomationRule extends Model
{
    public function all(): array
    {
        $stmt = $this->db->query('SELECT ar.*, u.name AS created_by_name FROM automation_rules ar LEFT JOIN users u ON u.id = ar.created_by ORDER BY ar.is_active DESC, ar.updated_at DESC, ar.id DESC');
        return $stmt->fetchAll();
    }

    public function active(string $triggerEvent = ''): array
    {
        $sql = 'SELECT * FROM automation_rules WHERE is_active = 1';
        $params = [];
        if ($triggerEvent !== '') {
            $sql .= ' AND trigger_event = ?';
            $params[] = $triggerEvent;
        }
        $sql .= ' ORDER BY sort_order ASC, id ASC';
        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll();
    }

    public function stats(): array
    {
        $row = $this->db->query('SELECT COUNT(*) total_count, SUM(is_active = 1) active_count, SUM(trigger_event = "event_webhook") webhook_count, MAX(last_run_at) last_run_at FROM automation_rules')->fetch();
        return $row ?: ['total_count' => 0, 'active_count' => 0, 'webhook_count' => 0, 'last_run_at' => null];
    }

    public function save(array $data): int
    {
        $name = trim((string)($data['name'] ?? ''));
        if ($name === '') {
            throw new RuntimeException('Automation rule name is required.');
        }
        $trigger = trim((string)($data['trigger_event'] ?? 'message_received')) ?: 'message_received';
        $condition = $this->encodeJson($data['condition_json'] ?? []);
        $action = $this->encodeJson($data['action_json'] ?? []);
        $sortOrder = (int)($data['sort_order'] ?? 100);
        $isActive = !empty($data['is_active']) ? 1 : 0;
        $id = (int)($data['id'] ?? 0);
        if ($id > 0) {
            $stmt = $this->db->prepare('UPDATE automation_rules SET name = ?, trigger_event = ?, condition_json = ?, action_json = ?, is_active = ?, sort_order = ?, updated_at = NOW() WHERE id = ?');
            $stmt->execute([$name, $trigger, $condition, $action, $isActive, $sortOrder, $id]);
            return $id;
        }
        $stmt = $this->db->prepare('INSERT INTO automation_rules (name, trigger_event, condition_json, action_json, is_active, sort_order, created_by) VALUES (?, ?, ?, ?, ?, ?, ?)');
        $stmt->execute([$name, $trigger, $condition, $action, $isActive, $sortOrder, (int)(current_user()['id'] ?? 0) ?: null]);
        return (int)$this->db->lastInsertId();
    }

    public function toggle(int $id): void
    {
        $stmt = $this->db->prepare('UPDATE automation_rules SET is_active = IF(is_active = 1, 0, 1), updated_at = NOW() WHERE id = ?');
        $stmt->execute([$id]);
    }

    public function delete(int $id): void
    {
        $stmt = $this->db->prepare('DELETE FROM automation_rules WHERE id = ?');
        $stmt->execute([$id]);
    }

    public function runForEvent(string $triggerEvent, array $context = []): array
    {
        $applied = [];
        foreach ($this->active($triggerEvent) as $rule) {
            if (!$this->matches($rule, $context)) {
                continue;
            }
            $actions = $this->decode((string)($rule['action_json'] ?? ''));
            $this->applyActions($actions, $context);
            $this->touchLastRun((int)$rule['id']);
            $applied[] = [
                'id' => (int)$rule['id'],
                'name' => (string)($rule['name'] ?? 'Rule'),
                'actions' => $actions,
            ];
        }
        return $applied;
    }

    public function matches(array $rule, array $context): bool
    {
        $conditions = $this->decode((string)($rule['condition_json'] ?? ''));
        foreach ($conditions as $field => $expected) {
            if ($expected === null || $expected === '') {
                continue;
            }
            $actual = $context[$field] ?? null;
            if (is_array($expected)) {
                if (!in_array($actual, $expected, true)) {
                    return false;
                }
                continue;
            }
            if ($field === 'contains') {
                $haystack = strtolower((string)($context['body'] ?? '')) . ' ' . strtolower((string)($context['subject'] ?? ''));
                if (!str_contains($haystack, strtolower((string)$expected))) {
                    return false;
                }
                continue;
            }
            if ($field === 'from_domain') {
                $domain = strtolower((string)substr(strrchr((string)($context['from_address'] ?? ''), '@'), 1));
                if ($domain !== strtolower((string)$expected)) {
                    return false;
                }
                continue;
            }
            if ((string)$actual !== (string)$expected) {
                return false;
            }
        }
        return true;
    }

    private function applyActions(array $actions, array $context): void
    {
        $conversationKey = trim((string)($context['conversation_key'] ?? ''));
        if ($conversationKey !== '') {
            $mailConversation = new MailConversation();
            $updates = [];
            if (!empty($actions['move_folder'])) {
                $updates['folder_key'] = (string)$actions['move_folder'];
            }
            if (!empty($actions['focus_bucket'])) {
                $updates['focus_bucket'] = (string)$actions['focus_bucket'];
            }
            if (!empty($actions['assign_user_id'])) {
                $updates['assigned_user_id'] = (int)$actions['assign_user_id'];
                $updates['claimed_by_user_id'] = (int)$actions['assign_user_id'];
                $updates['claimed_at'] = date('Y-m-d H:i:s');
            }
            if (!empty($actions['shared_mailbox_id'])) {
                $updates['shared_mailbox_id'] = (int)$actions['shared_mailbox_id'];
            }
            if (!empty($actions['snooze_hours'])) {
                $updates['snoozed_until'] = date('Y-m-d H:i:s', strtotime('+' . (int)$actions['snooze_hours'] . ' hours'));
                $updates['folder_key'] = 'snoozed';
            }
            if (!empty($actions['star'])) {
                $updates['is_starred'] = 1;
            }
            if (!empty($actions['mute'])) {
                $updates['is_muted'] = 1;
            }
            if (!empty($actions['pin'])) {
                $updates['is_pinned'] = 1;
            }
            if (!empty($actions['sensitivity_level'])) {
                $updates['sensitivity_level'] = (string)$actions['sensitivity_level'];
            }
            if ($updates) {
                $mailConversation->upsert($conversationKey, $updates);
            }
            if (!empty($actions['apply_label'])) {
                (new MailLabel())->ensureConversationLabels($conversationKey, [(string)$actions['apply_label']]);
            }
        }

        if (!empty($actions['pause_campaign']) && !empty($context['campaign_id'])) {
            (new Campaign())->setControlState((int)$context['campaign_id'], 'paused');
        }
        if (!empty($actions['force_queue']) && !empty($context['campaign_id'])) {
            (new QueueJob())->forceCampaignProcess((int)$context['campaign_id']);
        }
        if (!empty($actions['set_mail_transport'])) {
            (new Setting())->set('mail_transport', (string)$actions['set_mail_transport']);
        }
        if (!empty($actions['create_followup_task']) && !empty($context['contact_id'])) {
            try {
                require_once __DIR__ . '/ContactTask.php';
                (new ContactTask())->create([
                    'contact_id' => (int)$context['contact_id'],
                    'title' => (string)($actions['followup_title'] ?? 'Review conversation automation follow-up'),
                    'due_at' => date('Y-m-d H:i:s', strtotime('+1 day')),
                    'assigned_user_id' => !empty($actions['assign_user_id']) ? (int)$actions['assign_user_id'] : null,
                    'created_by' => (int)(current_user()['id'] ?? 0) ?: null,
                ]);
            } catch (Throwable $e) {
            }
        }
    }

    private function touchLastRun(int $id): void
    {
        $stmt = $this->db->prepare('UPDATE automation_rules SET last_run_at = NOW(), updated_at = NOW() WHERE id = ?');
        $stmt->execute([$id]);
    }

    private function decode(string $json): array
    {
        $data = json_decode($json, true);
        return is_array($data) ? $data : [];
    }

    private function encodeJson($value): string
    {
        if (is_string($value)) {
            $decoded = json_decode($value, true);
            if (is_array($decoded)) {
                $value = $decoded;
            } else {
                $value = ['value' => $value];
            }
        }
        return json_encode(is_array($value) ? $value : [], JSON_UNESCAPED_SLASHES);
    }
}
