<?php
require_once __DIR__ . '/../Core.php';

class MailConversation extends Model
{
    private const BUCKETS = ['focused', 'other'];
    private const SLA = ['normal', 'watch', 'due_soon', 'breached', 'resolved'];
    private const APPROVAL = ['not_required', 'pending', 'approved', 'rejected'];

    public function findByKey(string $conversationKey): ?array
    {
        $stmt = $this->db->prepare('SELECT * FROM mail_conversations WHERE conversation_key = ? LIMIT 1');
        $stmt->execute([$conversationKey]);
        return $stmt->fetch() ?: null;
    }

    public function indexedByKeys(array $keys): array
    {
        $keys = array_values(array_unique(array_filter(array_map('strval', $keys))));
        if (!$keys) {
            return [];
        }
        $placeholders = implode(',', array_fill(0, count($keys), '?'));
        $stmt = $this->db->prepare("SELECT * FROM mail_conversations WHERE conversation_key IN ($placeholders)");
        $stmt->execute($keys);
        $rows = [];
        foreach ($stmt->fetchAll() as $row) {
            $rows[(string)$row['conversation_key']] = $row;
        }
        return $rows;
    }

    public function ensure(string $conversationKey, array $defaults = []): array
    {
        $existing = $this->findByKey($conversationKey);
        if ($existing) {
            return $existing;
        }
        $stmt = $this->db->prepare('INSERT INTO mail_conversations (conversation_key, folder_key, focus_bucket, is_starred, is_archived, snoozed_until, assigned_user_id, shared_mailbox_id, sla_status, approval_status, approval_requested_user_id, approval_decided_user_id, approval_decided_at) VALUES (?, ?, ?, 0, 0, NULL, NULL, NULL, ?, ?, NULL, NULL, NULL)');
        $stmt->execute([
            $conversationKey,
            $defaults['folder_key'] ?? null,
            $this->normalizeBucket((string)($defaults['focus_bucket'] ?? 'focused')),
            $this->normalizeSla((string)($defaults['sla_status'] ?? 'normal')),
            $this->normalizeApproval((string)($defaults['approval_status'] ?? 'not_required')),
        ]);
        return $this->findByKey($conversationKey) ?: [
            'conversation_key' => $conversationKey,
            'folder_key' => $defaults['folder_key'] ?? null,
            'focus_bucket' => $this->normalizeBucket((string)($defaults['focus_bucket'] ?? 'focused')),
            'sla_status' => $this->normalizeSla((string)($defaults['sla_status'] ?? 'normal')),
            'approval_status' => $this->normalizeApproval((string)($defaults['approval_status'] ?? 'not_required')),
        ];
    }

    public function upsert(string $conversationKey, array $data): void
    {
        $current = $this->ensure($conversationKey, $data);
        $merged = [
            'folder_key' => array_key_exists('folder_key', $data) ? ($data['folder_key'] ?: null) : ($current['folder_key'] ?? null),
            'focus_bucket' => array_key_exists('focus_bucket', $data) ? $this->normalizeBucket((string)$data['focus_bucket']) : ($current['focus_bucket'] ?? 'focused'),
            'is_starred' => array_key_exists('is_starred', $data) ? (!empty($data['is_starred']) ? 1 : 0) : (int)($current['is_starred'] ?? 0),
            'is_archived' => array_key_exists('is_archived', $data) ? (!empty($data['is_archived']) ? 1 : 0) : (int)($current['is_archived'] ?? 0),
            'snoozed_until' => array_key_exists('snoozed_until', $data) ? ($data['snoozed_until'] ?: null) : ($current['snoozed_until'] ?? null),
            'assigned_user_id' => array_key_exists('assigned_user_id', $data) ? ((int)$data['assigned_user_id'] ?: null) : ((int)($current['assigned_user_id'] ?? 0) ?: null),
            'shared_mailbox_id' => array_key_exists('shared_mailbox_id', $data) ? ((int)$data['shared_mailbox_id'] ?: null) : ((int)($current['shared_mailbox_id'] ?? 0) ?: null),
            'sla_status' => array_key_exists('sla_status', $data) ? $this->normalizeSla((string)$data['sla_status']) : ($current['sla_status'] ?? 'normal'),
            'approval_status' => array_key_exists('approval_status', $data) ? $this->normalizeApproval((string)$data['approval_status']) : ($current['approval_status'] ?? 'not_required'),
            'approval_requested_user_id' => array_key_exists('approval_requested_user_id', $data) ? ((int)$data['approval_requested_user_id'] ?: null) : ((int)($current['approval_requested_user_id'] ?? 0) ?: null),
            'approval_decided_user_id' => array_key_exists('approval_decided_user_id', $data) ? ((int)$data['approval_decided_user_id'] ?: null) : ((int)($current['approval_decided_user_id'] ?? 0) ?: null),
            'approval_decided_at' => array_key_exists('approval_decided_at', $data) ? ($data['approval_decided_at'] ?: null) : ($current['approval_decided_at'] ?? null),
        ];
        $stmt = $this->db->prepare('UPDATE mail_conversations SET folder_key = ?, focus_bucket = ?, is_starred = ?, is_archived = ?, snoozed_until = ?, assigned_user_id = ?, shared_mailbox_id = ?, sla_status = ?, approval_status = ?, approval_requested_user_id = ?, approval_decided_user_id = ?, approval_decided_at = ?, updated_at = NOW() WHERE conversation_key = ?');
        $stmt->execute([
            $merged['folder_key'],
            $merged['focus_bucket'],
            $merged['is_starred'],
            $merged['is_archived'],
            $merged['snoozed_until'],
            $merged['assigned_user_id'],
            $merged['shared_mailbox_id'],
            $merged['sla_status'],
            $merged['approval_status'],
            $merged['approval_requested_user_id'],
            $merged['approval_decided_user_id'],
            $merged['approval_decided_at'],
            $conversationKey,
        ]);
    }

    public function toggleStar(string $conversationKey): bool
    {
        $row = $this->ensure($conversationKey);
        $new = empty($row['is_starred']) ? 1 : 0;
        $this->upsert($conversationKey, ['is_starred' => $new]);
        return (bool)$new;
    }

    public function archive(string $conversationKey, bool $archived = true): void
    {
        $this->upsert($conversationKey, [
            'is_archived' => $archived ? 1 : 0,
            'folder_key' => $archived ? 'archive' : null,
            'snoozed_until' => null,
        ]);
    }

    public function snooze(string $conversationKey, ?string $until): void
    {
        $this->upsert($conversationKey, [
            'folder_key' => $until ? 'snoozed' : null,
            'snoozed_until' => $until,
            'is_archived' => 0,
        ]);
    }

    public function normalizeBucket(string $bucket): string
    {
        $bucket = strtolower(trim($bucket));
        return in_array($bucket, self::BUCKETS, true) ? $bucket : 'focused';
    }

    public function normalizeSla(string $status): string
    {
        $status = strtolower(trim($status));
        return in_array($status, self::SLA, true) ? $status : 'normal';
    }

    public function normalizeApproval(string $status): string
    {
        $status = strtolower(trim($status));
        return in_array($status, self::APPROVAL, true) ? $status : 'not_required';
    }
}
