<?php

declare(strict_types=1);

class FrontAuthController
{
    public static function routes(): void
    {
        Router::get('/account', [self::class, 'account']);
        Router::get('/login', [self::class, 'loginRedirect']);
        Router::post('/login', [self::class, 'login']);
        Router::get('/register', [self::class, 'registerRedirect']);
        Router::post('/register', [self::class, 'register']);
        Router::post('/forgot-password', [self::class, 'forgotPassword']);
        Router::get('/reset-password', [self::class, 'showResetForm']);
        Router::post('/reset-password', [self::class, 'resetPassword']);
        Router::get('/logout', [self::class, 'logout']);
        Router::get('/profile', [self::class, 'profile']);
        Router::post('/profile', [self::class, 'updateProfile']);
    }

    private static function isAjax(): bool
    {
        return ($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '') === 'XMLHttpRequest';
    }

    private static function json(array $data, int $code = 200): void
    {
        http_response_code($code);
        header('Content-Type: application/json');
        echo json_encode($data);
        exit;
    }

    public static function account(): void
    {
        Router::redirect('/');
    }

    public static function loginRedirect(): void
    {
        Router::redirect('/');
    }

    public static function registerRedirect(): void
    {
        Router::redirect('/');
    }

    public static function login(): void
    {
        if (!Router::verifyCsrf()) {
            if (self::isAjax()) { self::json(['success' => false, 'error' => __('error_invalid_token')], 422); }
            Router::redirect('/');
            return;
        }

        if (!RateLimiter::throttle('login', 5, 20)) {
            if (self::isAjax()) { self::json(['success' => false, 'error' => __('too_many_requests')], 429); }
            Router::redirect('/');
            return;
        }

        $result = Auth::login($_POST['login'] ?? '', $_POST['password'] ?? '');

        if (self::isAjax()) {
            if ($result['success']) {
                self::json(['success' => true]);
            } else {
                self::json(['success' => false, 'error' => $result['error']], 422);
            }
        }

        if ($result['success']) {
            Router::redirect('/');
        } else {
            Router::redirect('/');
        }
    }

    public static function register(): void
    {
        if (!Router::verifyCsrf()) {
            if (self::isAjax()) { self::json(['success' => false, 'error' => __('error_invalid_token')], 422); }
            Router::redirect('/');
            return;
        }

        if (!RateLimiter::throttle('register', 5, 20)) {
            if (self::isAjax()) { self::json(['success' => false, 'error' => __('too_many_requests')], 429); }
            Router::redirect('/');
            return;
        }

        if (Setting::get('registration_enabled', '1') !== '1') {
            if (self::isAjax()) { self::json(['success' => false, 'error' => __('error_registration_disabled')], 422); }
            Router::redirect('/');
            return;
        }

         
        if (!Captcha::verify('register')) {
            if (self::isAjax()) { self::json(['success' => false, 'error' => __('error_captcha_failed')], 422); }
            Router::redirect('/');
            return;
        }

        $password = $_POST['password'] ?? '';
        $confirm = $_POST['password_confirm'] ?? '';

        if ($password !== $confirm) {
            if (self::isAjax()) { self::json(['success' => false, 'error' => __('error_passwords_mismatch')], 422); }
            Router::redirect('/');
            return;
        }

        $result = Auth::register($_POST['username'] ?? '', $_POST['email'] ?? '', $password);

        if (is_array($result) && !empty($result['success'])) {
            Telegram::notifyUser([
                'username' => (string) ($_POST['username'] ?? ''),
                'email'    => (string) ($_POST['email'] ?? ''),
            ]);
        }

        if (self::isAjax()) {
            if ($result['success']) {
                self::json(['success' => true]);
            } else {
                self::json(['success' => false, 'error' => $result['error']], 422);
            }
        }

        Router::redirect('/');
    }

    public static function forgotPassword(): void
    {
        if (!Router::verifyCsrf()) {
            if (self::isAjax()) { self::json(['success' => false, 'error' => __('error_invalid_token')], 422); }
            Router::redirect('/');
            return;
        }

        if (!RateLimiter::throttle('forgot_password', 3, 10)) {
            if (self::isAjax()) { self::json(['success' => true, 'message' => __('forgot_password_sent')]); }
            Router::redirect('/');
            return;
        }

        $email = trim($_POST['email'] ?? '');

        if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            if (self::isAjax()) { self::json(['success' => false, 'error' => __('error_invalid_email_address')], 422); }
            Router::redirect('/');
            return;
        }

         
        $user = User::findByEmail($email);
        if ($user) {
            $token = bin2hex(random_bytes(32));
            $expires = date('Y-m-d H:i:s', time() + 3600);
            Database::update('users', [
                'reset_token' => hash('sha256', $token),
                'reset_expires' => $expires,
            ], 'id = ?', [(int) $user['id']]);

            $siteUrl = rtrim(Setting::get('site_url', ''), '/');
            $resetUrl = $siteUrl . '/reset-password?token=' . $token;
            $primary = preg_match('/^#[0-9a-fA-F]{3,8}$/', (string) Setting::get('color_primary', '#6366f1'))
                ? (string) Setting::get('color_primary', '#6366f1') : '#6366f1';
            try {
                Mailer::sendType('password_reset', $email, [
                    '{site_name}'     => Setting::get('site_name', 'TubePress'),
                    '{username}'      => $user['username'],
                    '{reset_url}'     => $resetUrl,
                    '{primary_color}' => $primary,
                ]);
            } catch (\Throwable $e) {
                 
            }
        }

         
        if (self::isAjax()) {
            self::json(['success' => true, 'message' => __('forgot_password_sent')]);
        }

        Router::redirect('/');
    }

    public static function showResetForm(): void
    {
        $token = trim($_GET['token'] ?? '');
        $error = null;
        $valid = false;

        if ($token !== '') {
            $user = Database::fetchOne(
                'SELECT id FROM users WHERE reset_token = SHA2(?, 256) AND reset_expires > NOW()',
                [$token]
            );
            $valid = $user !== null;
        }

        if (!$valid) {
            $error = __('reset_token_invalid');
        }

        ThemeRenderer::render('auth/reset_password', [
            'pageTitle' => SEO::title(__('reset_password')),
            'token' => $token,
            'valid' => $valid,
            'error' => $error,
            'success' => null,
        ]);
    }

    public static function resetPassword(): void
    {
        if (!Router::verifyCsrf()) {
            Router::redirect('/reset-password');
            return;
        }

        $token = trim($_POST['token'] ?? '');
        $password = $_POST['password'] ?? '';
        $confirm = $_POST['password_confirm'] ?? '';

        if ($token === '') {
            Router::redirect('/');
            return;
        }

        $user = Database::fetchOne(
            'SELECT id FROM users WHERE reset_token = SHA2(?, 256) AND reset_expires > NOW()',
            [$token]
        );

        if (!$user) {
            ThemeRenderer::render('auth/reset_password', [
                'pageTitle' => SEO::title(__('reset_password')),
                'token' => $token,
                'valid' => false,
                'error' => __('reset_token_invalid'),
                'success' => null,
            ]);
            return;
        }

        if ($password === '' || mb_strlen($password) < 8) {
            ThemeRenderer::render('auth/reset_password', [
                'pageTitle' => SEO::title(__('reset_password')),
                'token' => $token,
                'valid' => true,
                'error' => __('error_password_length'),
                'success' => null,
            ]);
            return;
        }

        if ($password !== $confirm) {
            ThemeRenderer::render('auth/reset_password', [
                'pageTitle' => SEO::title(__('reset_password')),
                'token' => $token,
                'valid' => true,
                'error' => __('error_passwords_mismatch'),
                'success' => null,
            ]);
            return;
        }

         
        User::updatePassword((int) $user['id'], $password);
        Database::update('users', [
            'reset_token' => null,
            'reset_expires' => null,
        ], 'id = ?', [(int) $user['id']]);

        ThemeRenderer::render('auth/reset_password', [
            'pageTitle' => SEO::title(__('reset_password')),
            'token' => '',
            'valid' => false,
            'error' => null,
            'success' => __('reset_password_success'),
        ]);
    }

    public static function logout(): void
    {
        Auth::logout();
        Router::redirect('/');
    }

    public static function profile(): void
    {
        Auth::requireAuth();
        $tab = $_GET['tab'] ?? 'favorites';
        if (!in_array($tab, ['account', 'favorites', 'history', 'liked'], true)) {
            $tab = 'favorites';
        }

        $userId = Auth::id();
        $albumsOn = Setting::get('albums_enabled', '1') === '1';
         
        $ctype = is_string($_GET['type'] ?? null) ? $_GET['type'] : 'video';
        if (!$albumsOn || !in_array($ctype, ['video', 'album'], true)) {
            $ctype = 'video';
        }

         
        $favCount = Favorite::userFavoritesCount($userId);
        $likedCount = self::likedVideosCount($userId);
        $histCount = History::userHistoryCount($userId);
        $commentCount = Database::count('comments', 'user_id = ?', [$userId]);
        $albumFavCount = $albumsOn ? Album::userFavoritesCount($userId) : 0;
        $albumLikedCount = $albumsOn ? Album::userLikedCount($userId) : 0;

        $data = [
            'pageTitle' => SEO::title(__('my_profile')),
            'profileUser' => Auth::user(),
            'activeTab' => $tab,
            'contentType' => $ctype,
            'albumsEnabled' => $albumsOn,
            'error' => null,
            'success' => null,
            'favCount' => $favCount,
            'likedCount' => $likedCount,
            'histCount' => $histCount,
            'commentCount' => $commentCount,
            'albumFavCount' => $albumFavCount,
            'albumLikedCount' => $albumLikedCount,
            'favorites' => [],
            'favPagination' => null,
            'history' => [],
            'histPagination' => null,
            'liked' => [],
            'likedPagination' => null,
            'albumItems' => [],
            'albumPagination' => null,
        ];

        if ($tab === 'favorites') {
            if ($ctype === 'album') {
                $pagination = Pagination::fromRequest($albumFavCount, 24);
                $data['albumItems'] = Album::userFavorites($userId, 24, $pagination->offset);
                $data['albumPagination'] = $pagination;
            } else {
                $pagination = Pagination::fromRequest($favCount, 24);
                $data['favorites'] = Favorite::userFavorites($userId, 24, $pagination->offset);
                $data['favPagination'] = $pagination;
            }
        } elseif ($tab === 'history') {
            $pagination = Pagination::fromRequest($histCount, 24);
            $data['history'] = History::userHistory($userId, 24, $pagination->offset);
            $data['histPagination'] = $pagination;
        } elseif ($tab === 'liked') {
            if ($ctype === 'album') {
                $pagination = Pagination::fromRequest($albumLikedCount, 24);
                $data['albumItems'] = Album::userLiked($userId, 24, $pagination->offset);
                $data['albumPagination'] = $pagination;
            } else {
                $pagination = Pagination::fromRequest($likedCount, 24);
                $data['liked'] = self::likedVideos($userId, 24, $pagination->offset);
                $data['likedPagination'] = $pagination;
            }
        }

        ThemeRenderer::render('auth/profile', $data);
    }

    public static function updateProfile(): void
    {
        Auth::requireAuth();
        if (!Router::verifyCsrf()) { Router::redirect('/profile'); }

        $username = trim($_POST['username'] ?? '');
        $email = trim(strtolower($_POST['email'] ?? ''));

         
        if (mb_strlen($username) < 3 || mb_strlen($username) > 50) {
            self::renderProfile(__('error_username_length'), null);
            return;
        }
        if (!preg_match('/^[a-zA-Z0-9_-]+$/', $username)) {
            self::renderProfile(__('error_username_chars'), null);
            return;
        }

         
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            self::renderProfile(__('error_invalid_email'), null);
            return;
        }

         
        $existing = Database::fetchOne(
            'SELECT id FROM users WHERE (username = ? OR email = ?) AND id != ?',
            [$username, $email, Auth::id()]
        );
        if ($existing !== null) {
            self::renderProfile(__('error_username_taken'), null);
            return;
        }

        $data = ['username' => $username, 'email' => $email];

        if (!empty($_POST['password'])) {
             
            $currentPassword = $_POST['current_password'] ?? '';
            if ($currentPassword === '') {
                self::renderProfile(__('error_current_password_required'), null);
                return;
            }
            $user = User::find(Auth::id());
            if (!password_verify($currentPassword, $user['password_hash'])) {
                self::renderProfile(__('error_current_password_wrong'), null);
                return;
            }
            if (mb_strlen($_POST['password']) < 8) {
                self::renderProfile(__('error_password_length'), null);
                return;
            }
            if ($_POST['password'] !== ($_POST['password_confirm'] ?? '')) {
                self::renderProfile(__('error_passwords_mismatch'), null);
                return;
            }
            $data['password'] = $_POST['password'];
        }

        User::update(Auth::id(), $data);
        self::renderProfile(null, __('profile_updated'));
    }

    private static function renderProfile(?string $error, ?string $success): void
    {
        $userId = Auth::id();
        ThemeRenderer::render('auth/profile', [
            'pageTitle' => SEO::title(__('my_profile')),
            'profileUser' => User::find($userId),
            'activeTab' => 'account',
            'error' => $error,
            'success' => $success,
            'favCount' => Favorite::userFavoritesCount($userId),
            'likedCount' => self::likedVideosCount($userId),
            'histCount' => History::userHistoryCount($userId),
            'commentCount' => Database::count('comments', 'user_id = ?', [$userId]),
            'favorites' => [],
            'favPagination' => null,
            'history' => [],
            'histPagination' => null,
            'liked' => [],
            'likedPagination' => null,
        ]);
    }

    private static function likedVideos(int $userId, int $limit = 24, int $offset = 0): array
    {
        $results = Database::fetchAll(
            "SELECT v.*,
                    (SELECT p.name FROM video_performers vp
                     JOIN performers p ON vp.performer_id = p.id
                     WHERE vp.video_id = v.id ORDER BY p.name LIMIT 1) as performer_name
             FROM videos v
             JOIN video_likes vl ON v.id = vl.video_id
             WHERE vl.user_id = ? AND vl.type = ? AND v.status = ?
             ORDER BY vl.created_at DESC LIMIT ? OFFSET ?",
            [$userId, 'like', 'published', $limit, $offset]
        );
        return Video::localizeResults($results);
    }

    private static function likedVideosCount(int $userId): int
    {
        return Database::count('video_likes', 'user_id = ? AND type = ?', [$userId, 'like']);
    }
}
