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

class MailboxFolder extends Model
{
    private const SETTING_KEY = 'mailbox_custom_folders';
    private const RESERVED = ['inbox', 'outbox', 'sent', 'junk', 'trash'];

    public function systemFolders(): array
    {
        return [
            ['token' => 'inbox', 'name' => 'Inbox', 'system' => true, 'movable' => true],
            ['token' => 'outbox', 'name' => 'Outbox', 'system' => true, 'movable' => false],
            ['token' => 'sent', 'name' => 'Sent', 'system' => true, 'movable' => false],
            ['token' => 'junk', 'name' => 'Junk', 'system' => true, 'movable' => true],
            ['token' => 'trash', 'name' => 'Trash', 'system' => true, 'movable' => true],
        ];
    }

    public function customFolders(): array
    {
        $raw = json_decode((string)(new Setting())->get(self::SETTING_KEY, '[]'), true);
        if (!is_array($raw)) {
            return [];
        }
        $folders = [];
        foreach ($raw as $folder) {
            $slug = $this->slugify((string)($folder['slug'] ?? $folder['name'] ?? ''));
            $name = trim((string)($folder['name'] ?? ''));
            if ($slug === '' || $name === '' || in_array($slug, self::RESERVED, true)) {
                continue;
            }
            $folders[] = [
                'token' => $this->customToken($slug),
                'slug' => $slug,
                'name' => $name,
                'system' => false,
                'movable' => true,
            ];
        }
        usort($folders, static fn(array $a, array $b): int => strcasecmp((string)$a['name'], (string)$b['name']));
        return $folders;
    }

    public function moveDestinations(): array
    {
        $destinations = [
            ['token' => 'inbox', 'name' => 'Inbox'],
            ['token' => 'junk', 'name' => 'Junk'],
            ['token' => 'trash', 'name' => 'Trash'],
        ];
        foreach ($this->customFolders() as $folder) {
            $destinations[] = ['token' => $folder['token'], 'name' => $folder['name']];
        }
        return $destinations;
    }

    public function folderMeta(string $token): array
    {
        foreach (array_merge($this->systemFolders(), $this->customFolders()) as $folder) {
            if (($folder['token'] ?? '') === $token) {
                return $folder;
            }
        }
        if (str_starts_with($token, 'folder:')) {
            return [
                'token' => $token,
                'slug' => substr($token, 7),
                'name' => ucwords(str_replace(['-', '_'], ' ', substr($token, 7))),
                'system' => false,
                'movable' => true,
            ];
        }
        return ['token' => 'inbox', 'name' => 'Inbox', 'system' => true, 'movable' => true];
    }

    public function create(string $name): array
    {
        $name = trim($name);
        if ($name === '') {
            throw new RuntimeException('Folder name is required.');
        }
        $slug = $this->slugify($name);
        if ($slug === '') {
            throw new RuntimeException('Folder name must contain letters or numbers.');
        }
        if (in_array($slug, self::RESERVED, true)) {
            throw new RuntimeException('That folder name is reserved for a system mailbox.');
        }
        $existing = $this->customFolders();
        $baseSlug = $slug;
        $suffix = 2;
        $taken = array_column($existing, 'slug');
        while (in_array($slug, $taken, true)) {
            $slug = $baseSlug . '-' . $suffix;
            $suffix++;
        }
        $existing[] = [
            'token' => $this->customToken($slug),
            'slug' => $slug,
            'name' => $name,
            'system' => false,
            'movable' => true,
        ];
        $this->saveCustomFolders($existing);
        return [
            'token' => $this->customToken($slug),
            'slug' => $slug,
            'name' => $name,
            'system' => false,
            'movable' => true,
        ];
    }

    public function delete(string $slug): bool
    {
        $slug = $this->slugify($slug);
        if ($slug === '') {
            return false;
        }
        $existing = $this->customFolders();
        $remaining = array_values(array_filter($existing, static fn(array $folder): bool => (string)($folder['slug'] ?? '') !== $slug));
        if (count($remaining) === count($existing)) {
            return false;
        }
        $this->saveCustomFolders($remaining);
        return true;
    }

    public function normalizeDestination(string $token): string
    {
        $token = trim($token);
        foreach ($this->moveDestinations() as $folder) {
            if (($folder['token'] ?? '') === $token) {
                return $token;
            }
        }
        throw new RuntimeException('Select a valid destination folder.');
    }

    public function customToken(string $slug): string
    {
        return 'folder:' . $this->slugify($slug);
    }

    private function saveCustomFolders(array $folders): void
    {
        $payload = [];
        foreach ($folders as $folder) {
            $slug = $this->slugify((string)($folder['slug'] ?? $folder['name'] ?? ''));
            $name = trim((string)($folder['name'] ?? ''));
            if ($slug === '' || $name === '' || in_array($slug, self::RESERVED, true)) {
                continue;
            }
            $payload[] = ['slug' => $slug, 'name' => $name];
        }
        usort($payload, static fn(array $a, array $b): int => strcasecmp((string)$a['name'], (string)$b['name']));
        (new Setting())->set(self::SETTING_KEY, json_encode(array_values($payload)) ?: '[]');
    }

    private function slugify(string $value): string
    {
        $value = strtolower(trim($value));
        $value = preg_replace('/[^a-z0-9]+/', '-', $value) ?? '';
        return trim($value, '-');
    }
}
