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

class MailFolder extends Model
{
    private const SETTINGS_KEY = 'email_custom_folders_json';

    public function __construct()
    {
        parent::__construct();
        $this->ensureSystemFolders();
        $this->importLegacyFolders();
    }

    public function system(): array
    {
        return [
            ['key' => 'inbox', 'name' => 'Inbox', 'system' => true, 'parent_key' => null, 'sort_order' => 10],
            ['key' => 'outbox', 'name' => 'Outbox', 'system' => true, 'parent_key' => null, 'sort_order' => 20],
            ['key' => 'sent', 'name' => 'Sent', 'system' => true, 'parent_key' => null, 'sort_order' => 30],
            ['key' => 'junk', 'name' => 'Junk', 'system' => true, 'parent_key' => null, 'sort_order' => 40],
            ['key' => 'trash', 'name' => 'Trash', 'system' => true, 'parent_key' => null, 'sort_order' => 50],
            ['key' => 'archive', 'name' => 'Archive', 'system' => true, 'parent_key' => null, 'sort_order' => 60],
            ['key' => 'snoozed', 'name' => 'Snoozed', 'system' => true, 'parent_key' => null, 'sort_order' => 70],
        ];
    }

    public function all(): array
    {
        $stmt = $this->db->query('SELECT f.id, f.parent_id, f.folder_key AS `key`, f.name, f.is_system AS system, f.sort_order, p.folder_key AS parent_key
            FROM mail_folders f
            LEFT JOIN mail_folders p ON p.id = f.parent_id
            ORDER BY f.is_system DESC, COALESCE(p.sort_order, 0) ASC, COALESCE(p.name, "") ASC, f.sort_order ASC, f.name ASC');
        $rows = $stmt->fetchAll();
        if (!$rows) {
            return $this->system();
        }
        $byParent = [];
        foreach ($rows as $row) {
            $byParent[$row['parent_id'] !== null ? (string)$row['parent_id'] : 'root'][] = $row;
        }
        $flatten = function ($parentId = null, int $level = 0) use (&$flatten, &$byParent): array {
            $result = [];
            $key = $parentId !== null ? (string)$parentId : 'root';
            foreach ($byParent[$key] ?? [] as $row) {
                $row['system'] = !empty($row['system']);
                $row['level'] = $level;
                $row['display_name'] = str_repeat('— ', $level) . $row['name'];
                $result[] = $row;
                foreach ($flatten((int)$row['id'], $level + 1) as $child) {
                    $result[] = $child;
                }
            }
            return $result;
        };
        return $flatten(null, 0);
    }

    public function byKey(string $key): ?array
    {
        $key = $this->normalizeKey($key);
        foreach ($this->all() as $folder) {
            if (($folder['key'] ?? '') === $key) {
                return $folder;
            }
        }
        return null;
    }

    public function exists(string $key): bool
    {
        return $this->byKey($key) !== null;
    }

    public function create(string $name, ?string $parentKey = null): array
    {
        $name = trim($name);
        if ($name === '') {
            throw new RuntimeException('Folder name is required.');
        }
        $key = $this->normalizeKey($name);
        if ($key === '') {
            $key = 'folder-' . substr(md5($name . microtime(true)), 0, 8);
        }
        if ($this->exists($key)) {
            throw new RuntimeException('That folder already exists.');
        }
        $reserved = array_column($this->system(), 'key');
        if (in_array($key, $reserved, true)) {
            throw new RuntimeException('That folder name is reserved.');
        }
        $parentId = null;
        if ($parentKey) {
            $parent = $this->byKey($parentKey);
            if (!$parent) {
                throw new RuntimeException('Parent folder not found.');
            }
            $parentId = (int)($parent['id'] ?? 0) ?: null;
        }
        $stmt = $this->db->prepare('INSERT INTO mail_folders (parent_id, folder_key, name, is_system, sort_order, created_by) VALUES (?, ?, ?, 0, ?, ?)');
        $stmt->execute([$parentId, $key, $name, 100, (int)(current_user()['id'] ?? 0) ?: null]);
        return $this->byKey($key) ?: ['key' => $key, 'name' => $name, 'parent_key' => $parentKey, 'system' => false];
    }

    public function normalizeKey(string $key): string
    {
        $key = strtolower(trim($key));
        $key = preg_replace('/[^a-z0-9_-]+/', '-', $key) ?? '';
        return trim($key, '-_');
    }

    private function ensureSystemFolders(): void
    {
        foreach ($this->system() as $folder) {
            $stmt = $this->db->prepare('SELECT id FROM mail_folders WHERE folder_key = ? LIMIT 1');
            $stmt->execute([$folder['key']]);
            $id = $stmt->fetchColumn();
            if ($id) {
                $update = $this->db->prepare('UPDATE mail_folders SET name = ?, is_system = 1, sort_order = ? WHERE id = ?');
                $update->execute([$folder['name'], (int)$folder['sort_order'], (int)$id]);
                continue;
            }
            $insert = $this->db->prepare('INSERT INTO mail_folders (parent_id, folder_key, name, is_system, sort_order, created_by) VALUES (NULL, ?, ?, 1, ?, NULL)');
            $insert->execute([$folder['key'], $folder['name'], (int)$folder['sort_order']]);
        }
    }

    private function importLegacyFolders(): void
    {
        $count = (int)$this->db->query('SELECT COUNT(*) FROM mail_folders WHERE is_system = 0')->fetchColumn();
        if ($count > 0) {
            return;
        }
        $json = (new Setting())->get(self::SETTINGS_KEY, '[]');
        $rows = json_decode((string)$json, true);
        if (!is_array($rows) || !$rows) {
            return;
        }
        $stmt = $this->db->prepare('INSERT IGNORE INTO mail_folders (parent_id, folder_key, name, is_system, sort_order, created_by, created_at) VALUES (NULL, ?, ?, 0, 100, NULL, ?)');
        foreach ($rows as $row) {
            if (!is_array($row)) {
                continue;
            }
            $key = $this->normalizeKey((string)($row['key'] ?? $row['name'] ?? ''));
            $name = trim((string)($row['name'] ?? ''));
            if ($key === '' || $name === '') {
                continue;
            }
            $stmt->execute([$key, $name, $row['created_at'] ?? date('Y-m-d H:i:s')]);
        }
    }
}
