<?php

require_once __DIR__ . '/../../config/helpers.php';
require_once __DIR__ . '/../../middleware/auth.php';
require_once __DIR__ . '/InboxRepository.php';

class InboxService
{
    private PDO $pdo;
    private array $config;
    private InboxRepository $repo;

    public function __construct(PDO $pdo, array $config)
    {
        $this->pdo = $pdo;
        $this->config = $config;
        $this->repo = new InboxRepository($pdo);
    }

    public function getCurrentInboxContext(): array
    {
        $authUser = $this->tryRequireAuth();
        if ($authUser) {
            $primaryEmail = (string) ($authUser['email'] ?? '');
            if ($primaryEmail === '' && !empty($authUser['username'])) {
                $primaryEmail = buildUserInboxEmail((string) $authUser['username'], $this->config);
            }

            $primaryInbox = $this->repo->createUserInboxIfMissing((int) $authUser['id'], $primaryEmail);
            $inboxes = $this->repo->listActiveInboxesForUser((int) $authUser['id']);
            clearGuestInboxCookie($this->config);

            return [
                'mode' => 'user',
                'user' => $authUser,
                'inbox' => $primaryInbox,
                'inboxes' => $inboxes,
            ];
        }

        $guestInbox = $this->resolveGuestInbox();
        return [
            'mode' => 'guest',
            'user' => null,
            'inbox' => $guestInbox,
            'inboxes' => [$guestInbox],
        ];
    }

    public function tryRequireAuth(): ?array
    {
        $token = getRequestToken($this->config);
        if (!$token) {
            return null;
        }

        $tokenHash = hashToken($token);
        $stmt = $this->pdo->prepare(
            "SELECT us.id AS session_id, us.user_id, us.expires_at, us.is_revoked,
                    u.id, u.name, u.username, u.email, u.phone, u.avatar, u.country, u.agent, u.ip, u.is_active, u.role, u.created_at, u.updated_at
             FROM user_sessions us
             INNER JOIN users u ON u.id = us.user_id
             WHERE us.token_hash = :token_hash
             LIMIT 1"
        );
        $stmt->execute(['token_hash' => $tokenHash]);
        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$user) {
            return null;
        }
        if ((int) ($user['is_revoked'] ?? 0) === 1) {
            return null;
        }
        if (strtotime((string) $user['expires_at']) < time()) {
            return null;
        }
        if ((int) ($user['is_active'] ?? 0) !== 1) {
            return null;
        }

        $touch = $this->pdo->prepare('UPDATE user_sessions SET last_seen_at = NOW() WHERE id = :id');
        $touch->execute(['id' => $user['session_id']]);

        return sanitizeUser($user);
    }

    public function resolveGuestInbox(): array
    {
        $token = getGuestInboxAccessToken($this->config);
        if ($token) {
            $existing = $this->repo->findGuestInboxByToken($token);
            if ($existing && (int) ($existing['is_active'] ?? 0) === 1) {
                $expiresAtTs = !empty($existing['expires_at']) ? strtotime((string) $existing['expires_at']) : 0;
                if ($expiresAtTs > time()) {
                    setGuestInboxCookie($this->config, $token, $expiresAtTs);
                }
                return $existing;
            }
        }

        return $this->createFreshGuestInbox();
    }

    public function discardCurrentGuestInbox(): ?array
    {
        $token = getGuestInboxAccessToken($this->config);
        if (!$token) {
            clearGuestInboxCookie($this->config);
            return null;
        }

        $guestInbox = $this->repo->findGuestInboxByToken($token);
        if ($guestInbox && (int) ($guestInbox['user_id'] ?? 0) === 0 && ($guestInbox['type'] ?? '') === 'guest') {
            $this->repo->discardGuestInbox((int) $guestInbox['id']);
        }

        clearGuestInboxCookie($this->config);
        return $guestInbox ?: null;
    }

    public function createFreshGuestInbox(): array
    {
        $ttlHours = max(1, (int) ($this->config['guest_inbox']['ttl_hours'] ?? 2));
        $expiresAtTs = strtotime('+' . $ttlHours . ' hours');
        $expiresAt = date('Y-m-d H:i:s', $expiresAtTs);

        do {
            $emailAddress = generateGuestEmailAddress($this->config);
            $collision = $this->repo->findInboxByEmail($emailAddress);
        } while ($collision);

        $token = generateToken(16);
        $inbox = $this->repo->createGuestInbox($emailAddress, $token, $expiresAt);
        setGuestInboxCookie($this->config, $token, $expiresAtTs);
        return $inbox;
    }

    public function ensureUserInbox(int $userId, string $emailAddress): array
    {
        return $this->repo->createUserInboxIfMissing($userId, $emailAddress);
    }

    public function applyGuestInboxDecision(int $userId, string $emailAddress, ?string $guestToken, string $guestAction = 'fresh'): array
    {
        $userInbox = $this->ensureUserInbox($userId, $emailAddress);
        $guestAction = strtolower(trim($guestAction));

        if (!$guestToken) {
            return $userInbox;
        }

        $guestInbox = $this->repo->findGuestInboxByToken($guestToken);
        if (!$guestInbox || (int) ($guestInbox['is_active'] ?? 0) !== 1) {
            return $userInbox;
        }

        if ($guestAction !== 'transfer') {
            if ((int) ($guestInbox['user_id'] ?? 0) === 0 && ($guestInbox['type'] ?? '') === 'guest') {
                $this->repo->discardGuestInbox((int) $guestInbox['id']);
            }
            clearGuestInboxCookie($this->config);
            return $userInbox;
        }

        if ((int) ($guestInbox['id'] ?? 0) === (int) ($userInbox['id'] ?? 0)) {
            return $userInbox;
        }

        $this->repo->transferGuestInboxToUser((int) $guestInbox['id'], $userId);
        clearGuestInboxCookie($this->config);
        return $this->repo->findInboxById((int) $userInbox['id']) ?: $userInbox;
    }
}
