<?php

namespace App\Http\Controllers\Website;

use App\Http\Controllers\Controller;
use App\Models\DownloadItem;
use App\Models\Event;
use App\Models\EventClaim;
use App\Models\News;
use App\Models\TopspenderCharacterCache;
use App\Services\Analytics\StatsService;
use App\Services\Api\API;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Inertia\Inertia;
use Inertia\Response;

class WebsiteController extends Controller
{
    protected API $api;

    public function __construct(
        API $api,
        private readonly StatsService $statsService
    ) {
        $this->api = $api;
    }

    protected array $classNames = [
        0 => 'Blademaster',
        1 => 'Mage',
        2 => 'Psychic',
        3 => 'Venomancer',
        4 => 'Barbarian',
        5 => 'Assassin',
        6 => 'Archer',
        7 => 'Cleric',
        8 => 'Seeker',
        9 => 'Mystic',
        10 => 'Duskblade',
        11 => 'Stormbringer',
        12 => 'Technician',
        13 => 'Edgerunner',
        14 => 'Wildwalker',
    ];

    /**
     * Get the character most frequently used for top-ups by counting transactions
     */
    private function getMostFrequentTopupCharacter(int $userId, int $month, int $year): array
    {
        $ipaymuChars = DB::table('ipaymu_transactions')
            ->select('character_id', DB::raw('COUNT(*) as transaction_count'), DB::raw('SUM(amount) as total_amount'))
            ->where('user_id', $userId)
            ->where('status', 'success')
            ->whereNotNull('character_id')
            ->whereMonth('created_at', $month)
            ->whereYear('created_at', $year)
            ->groupBy('character_id');

        $duitkuChars = DB::table('duitku_transactions')
            ->select('character_id', DB::raw('COUNT(*) as transaction_count'), DB::raw('SUM(amount) as total_amount'))
            ->where('user_id', $userId)
            ->where('status', 'success')
            ->whereNotNull('character_id')
            ->whereMonth('created_at', $month)
            ->whereYear('created_at', $year)
            ->groupBy('character_id');

        $tripayChars = DB::table('tripay_transactions')
            ->select('character_id', DB::raw('COUNT(*) as transaction_count'), DB::raw('SUM(amount) as total_amount'))
            ->where('user_id', $userId)
            ->where('status', 'paid')
            ->whereNotNull('character_id')
            ->whereMonth('created_at', $month)
            ->whereYear('created_at', $year)
            ->groupBy('character_id');

        $pakasirChars = DB::table('pakasir_transactions')
            ->select('character_id', DB::raw('COUNT(*) as transaction_count'), DB::raw('SUM(amount) as total_amount'))
            ->where('user_id', $userId)
            ->where('status', 'success')
            ->whereNotNull('character_id')
            ->whereMonth('created_at', $month)
            ->whereYear('created_at', $year)
            ->groupBy('character_id');

        $allChars = $ipaymuChars
            ->unionAll($duitkuChars)
            ->unionAll($tripayChars)
            ->unionAll($pakasirChars);

        $mostUsedChar = DB::table(DB::raw("({$allChars->toSql()}) as char_counts"))
            ->mergeBindings($allChars)
            ->select('character_id', DB::raw('SUM(transaction_count) as total_count'), DB::raw('SUM(total_amount) as total_amount'))
            ->groupBy('character_id')
            ->orderBy('total_amount', 'desc')
            ->orderBy('total_count', 'desc')
            ->first();

        if (! $mostUsedChar || ! $mostUsedChar->character_id) {
            return $this->getMostUsedCharacter($userId, $month, $year);
        }

        $characterId = $mostUsedChar->character_id;

        try {
            $roleBase = $this->api->getRoleBase($characterId);
            if ($roleBase && isset($roleBase['name'])) {
                // Cache successful API response for offline fallback
                TopspenderCharacterCache::storeCache(
                    $userId,
                    $month,
                    $year,
                    $roleBase['name'],
                    $roleBase['cls'] ?? null
                );

                return [
                    'id' => $characterId,
                    'name' => $roleBase['name'],
                    'class' => $roleBase['cls'] ?? null,
                ];
            }
        } catch (\Exception $e) {
            // API offline: try cache first before falling back
            $cached = TopspenderCharacterCache::getCachedCharacter($userId, $month, $year);
            if ($cached) {
                return [
                    'id' => $characterId,
                    'name' => $cached->character_name,
                    'class' => $cached->character_class,
                ];
            }
        }

        return $this->getMostUsedCharacter($userId, $month, $year);
    }

    /**
     * Get the first active character for a user
     */
    private function getMostUsedCharacter(int $userId, int $month, int $year): array
    {
        // Try cache first — useful when server is offline
        $cached = TopspenderCharacterCache::getCachedCharacter($userId, $month, $year);
        if ($cached) {
            return [
                'id' => $userId,
                'name' => $cached->character_name,
                'class' => $cached->character_class,
            ];
        }

        try {
            $roles = $this->api->getRoles($userId);
            if (isset($roles['roles']) && ! empty($roles['roles'])) {
                foreach ($roles['roles'] as $role) {
                    if (isset($role['id']) && $role['id'] > 0) {
                        $characterId = $role['id'];
                        $characterName = $role['name'] ?? 'Unknown';
                        $characterClass = null;

                        try {
                            $roleBase = $this->api->getRoleBase($characterId);
                            if ($roleBase && isset($roleBase['cls'])) {
                                $characterClass = $roleBase['cls'];
                            }
                        } catch (\Exception $e) {
                        }

                        // Cache the resolved character for offline fallback
                        TopspenderCharacterCache::storeCache(
                            $userId,
                            $month,
                            $year,
                            $characterName,
                            $characterClass
                        );

                        return [
                            'id' => $characterId,
                            'name' => $characterName,
                            'class' => $characterClass,
                        ];
                    }
                }
            }
        } catch (\Exception $e) {
            // API offline and no cache — fall through to truename fallback
        }

        $user = DB::table('users')->select('truename')->where('ID', $userId)->first();

        return [
            'id' => $userId,
            'name' => $user->truename ?? 'Unknown',
            'class' => null,
        ];
    }

    /**
     * Get top 10 spenders for widget
     */
    private function getTopSpenders(int $limit = 10): array
    {
        $month = now()->month;
        $year = now()->year;

        $ipaymuQuery = DB::table('ipaymu_transactions')->select('user_id', 'amount')->where('status', 'success')->whereMonth('created_at', $month)->whereYear('created_at', $year);
        $duitkuQuery = DB::table('duitku_transactions')->select('user_id', 'amount')->where('status', 'success')->whereMonth('created_at', $month)->whereYear('created_at', $year);
        $tripayQuery = DB::table('tripay_transactions')->select('user_id', 'amount')->where('status', 'paid')->whereMonth('created_at', $month)->whereYear('created_at', $year);
        $pakasirQuery = DB::table('pakasir_transactions')->select('user_id', 'amount')->where('status', 'success')->whereMonth('created_at', $month)->whereYear('created_at', $year);

        $allTransactions = $ipaymuQuery->unionAll($duitkuQuery)->unionAll($tripayQuery)->unionAll($pakasirQuery);

        $results = DB::table(DB::raw("({$allTransactions->toSql()}) as all_transactions"))
            ->mergeBindings($allTransactions)
            ->select('all_transactions.user_id', DB::raw('SUM(all_transactions.amount) as total_amount'))
            ->join('users', 'all_transactions.user_id', '=', 'users.ID')
            ->groupBy('all_transactions.user_id')
            ->orderBy('total_amount', 'desc')
            ->limit($limit)
            ->get();

        $topSpenders = [];
        $rank = 1;

        foreach ($results as $item) {
            $characterData = $this->getMostFrequentTopupCharacter($item->user_id, $month, $year);

            // Keep the 'id' key as 'id' which the widget reads, but pass the actual character ID.
            $roleId = $characterData['id'];
            // Get the character name
            $name = $characterData['name'];
            $classId = $characterData['class'] ?? 0;
            $className = $this->classNames[$classId] ?? 'Unknown';

            $topSpenders[] = [
                'id' => $roleId > 0 ? $roleId : $item->user_id,
                'rank' => $rank++,
                'name' => $name,
                'class' => $classId,
                'class_name' => $className,
                'amount' => (int) $item->total_amount,
            ];
        }

        return $topSpenders;
    }

    public function index(): Response
    {
        $onlineData = $this->statsService->getOnlineData();
        $timezone = $this->statsService->getServerTimezone();
        $totalAccounts = $this->statsService->getTotalUsers();

        // Get application name from .env config
        $appName = config('app.name', 'Perfect World');

        // Get Discord Server ID from settings
        $discordServerId = DB::table('settings')->where('key', 'discord_server_id')->value('value') ?? '';

        // Get active download items for dialog
        $downloadItems = DownloadItem::active()->ordered()->get();

        // Get latest 3 active news articles
        $latestNews = News::where('is_active', true)
            ->orderBy('created_at', 'desc')
            ->take(3)
            ->get();

        // Get GM list with online status
        $gmList = $this->getGMList();

        // Get top 10 spenders for widget
        $topSpenders = $this->getTopSpenders(10);

        // Get active events for event section
        $user = Auth::user();
        $userId = $user ? $user->ID : null;

        $activeEvents = Event::getActiveEvents()->map(function ($event) use ($userId) {
            $eventData = [
                'id' => $event->id,
                'name' => $event->name,
                'item_id' => $event->item_id,
                'item_name' => $event->item_name,
                'item_count' => $event->item_count,
            ];

            // Add claim status if user is logged in
            if ($userId) {
                $eventData['is_claimed'] = EventClaim::hasUserClaimed($userId, $event->id);
                $eventData['is_eligible'] = $event->isUserEligible($userId);
            }

            return $eventData;
        })->toArray();

        // Get user characters if logged in
        $userCharacters = [];
        if ($userId) {
            try {
                $roles = $this->api->getRoles($userId);
                if (isset($roles['roles']) && ! empty($roles['roles'])) {
                    foreach ($roles['roles'] as $role) {
                        if (isset($role['id']) && $role['id'] > 0) {
                            $userCharacters[] = [
                                'id' => $role['id'],
                                'name' => $role['name'] ?? 'Unknown',
                            ];
                        }
                    }
                }
            } catch (\Exception $e) {
                Log::error('Failed to get user characters for homepage: '.$e->getMessage());
            }
        }

        // Get background paths first
        $heroBgPath = DB::table('settings')->where('key', 'hero_background')->value('value');
        $communityBgPath = DB::table('settings')->where('key', 'community_background')->value('value');
        $newsBgPath = DB::table('settings')->where('key', 'news_background')->value('value');
        $downloadBgPath = DB::table('settings')->where('key', 'download_background')->value('value');

        // Generate WebP versions for hero background if available
        $heroBgWebP = null;
        if ($heroBgPath) {
            $pathInfo = pathinfo($heroBgPath);
            $webpPath = $pathInfo['dirname'].'/'.$pathInfo['filename'].'.webp';
            if (file_exists(public_path($webpPath))) {
                $heroBgWebP = asset($webpPath);
            }
        }

        // Get smoke animation enabled setting (hero section - disabled by default)
        $smokeEnabled = DB::table('settings')->where('key', 'smoke_enabled')->value('value') === '1';

        // Get news section smoke animation enabled setting
        $newsSmokeEnabled = DB::table('settings')->where('key', 'news_smoke_enabled')->value('value') === '1';

        // Get news section sparks animation enabled setting
        $newsSparksEnabled = DB::table('settings')->where('key', 'news_sparks_enabled')->value('value') === '1';

        // Get app name color (default: amber-400)
        $appNameColor = DB::table('settings')->where('key', 'app_name_color')->value('value') ?? '#fbbf24';

        // Get server start time for countdown
        $serverStartTime = DB::table('settings')->where('key', 'server_start_time')->value('value');

        // Get hero use logo setting
        $heroUseLogo = DB::table('settings')->where('key', 'hero_use_logo')->value('value') === '1';

        // Get app logo path
        $logoPath = DB::table('settings')->where('key', 'app_logo')->value('value');
        $heroLogoUrl = $logoPath ? asset($logoPath) : null;

        // Get hero logo size (default: 300px)
        $heroLogoSize = (int) (DB::table('settings')->where('key', 'hero_logo_size')->value('value') ?? 300);

        // Get server rates from database
        $serverRates = DB::table('server_rates')->first();
        $expRate = $serverRates->exp_rate ?? 1;
        $doubleDrop = (bool) ($serverRates->double_drop ?? 0);

        return Inertia::render('website/index', [
            'serverInfo' => [
                'onlinePlayers' => $onlineData['count'],
                'gmOnline' => $onlineData['gms'] ?? 0,
                'serverTime' => Carbon::now($timezone)->format('H:i:s'),
                'serverDate' => Carbon::now($timezone)->format('d M Y'),
                'timezone' => $timezone,
                'totalAccounts' => $totalAccounts,
                'serverOnline' => $onlineData['serverOnline'] ?? false,
                'appName' => $appName,
                'discordServerId' => $discordServerId,
                'heroBackgroundUrl' => $heroBgPath ? asset($heroBgPath) : null,
                'heroBackgroundWebP' => $heroBgWebP,
                'communityBackgroundUrl' => $communityBgPath ? asset($communityBgPath) : null,
                'newsBackgroundUrl' => $newsBgPath ? asset($newsBgPath) : null,
                'downloadBackgroundUrl' => $downloadBgPath ? asset($downloadBgPath) : null,
                'heroHeight' => (int) (DB::table('settings')->where('key', 'hero_height')->value('value') ?? 40),
                'smokeEnabled' => $smokeEnabled,
                'newsSmokeEnabled' => $newsSmokeEnabled,
                'newsSparksEnabled' => $newsSparksEnabled,
                'appNameColor' => $appNameColor,
                'serverStartTime' => $serverStartTime,
                'heroUseLogo' => $heroUseLogo,
                'heroLogoUrl' => $heroLogoUrl,
                'heroLogoSize' => $heroLogoSize,
                'expRate' => $expRate,
                'doubleDrop' => $doubleDrop,
            ],
            'downloadItems' => $downloadItems,
            'latestNews' => $latestNews,
            'gmList' => $gmList,
            'topSpenders' => $topSpenders,
            'activeEvents' => $activeEvents,
            'userCharacters' => $userCharacters,
        ]);
    }

    /**
     * Get GM list with online status
     */
    private function getGMList(): array
    {
        // Get GM accounts by joining auth table with users table (same as admin GM management)
        $gmAccounts = DB::table('auth')
            ->join('users', 'auth.userid', '=', 'users.ID')
            ->select('users.ID', 'users.truename', 'users.photo', DB::raw('GROUP_CONCAT(auth.rid) as permissions'))
            ->groupBy('users.ID', 'users.truename', 'users.photo')
            ->get();

        try {
            // Get online list from API
            $onlineList = $this->api->getOnlineList();
            $onlineRoleIds = array_column($onlineList, 'roleid');

            $gmList = [];
            foreach ($gmAccounts as $gm) {
                // Check if GM has a character online
                $isOnline = false;
                try {
                    $rolesData = $this->api->getRoles($gm->ID);
                    $roles = $rolesData['roles'] ?? [];

                    foreach ($roles as $role) {
                        if (in_array($role['id'], $onlineRoleIds)) {
                            $isOnline = true;
                            break;
                        }
                    }
                } catch (\Exception $e) {
                    // If API fails, assume offline
                    $isOnline = false;
                }

                $gmList[] = [
                    'id' => $gm->ID,
                    'truename' => $gm->truename,
                    'profilePhotoUrl' => $gm->photo ? asset($gm->photo) : asset('img/iconclass/0.png'),
                    'online' => $isOnline,
                ];
            }

            return $gmList;
        } catch (\Exception $e) {
            // Fallback: return all GMs as offline
            return $gmAccounts->map(function ($gm) {
                return [
                    'id' => $gm->ID,
                    'truename' => $gm->truename,
                    'profilePhotoUrl' => $gm->photo ? asset($gm->photo) : asset('img/iconclass/0.png'),
                    'online' => false,
                ];
            })->toArray();
        }
    }

    /**
     * Display the download page
     */
    public function download(): Response
    {
        $onlineData = $this->statsService->getOnlineData();
        $timezone = $this->statsService->getServerTimezone();
        $totalAccounts = $this->statsService->getTotalUsers();

        // Get application name from .env config
        $appName = config('app.name', 'Perfect World');

        // Get Discord Server ID from settings
        $discordServerId = DB::table('settings')->where('key', 'discord_server_id')->value('value') ?? '';

        // Get active download items
        $downloadItems = DownloadItem::active()->ordered()->get();

        // Get GM list with online status
        $gmList = $this->getGMList();

        // Get top 10 spenders for widget
        $topSpenders = $this->getTopSpenders(10);

        // Get background paths
        $heroBgPath = DB::table('settings')->where('key', 'hero_background')->value('value');
        $communityBgPath = DB::table('settings')->where('key', 'community_background')->value('value');
        $newsBgPath = DB::table('settings')->where('key', 'news_background')->value('value');
        $downloadBgPath = DB::table('settings')->where('key', 'download_background')->value('value');

        // Generate WebP versions for hero background if available
        $heroBgWebP = null;
        if ($heroBgPath) {
            $pathInfo = pathinfo($heroBgPath);
            $webpPath = $pathInfo['dirname'].'/'.$pathInfo['filename'].'.webp';
            if (file_exists(public_path($webpPath))) {
                $heroBgWebP = asset($webpPath);
            }
        }

        // Get smoke animation enabled setting (hero section - disabled by default)
        $smokeEnabled = DB::table('settings')->where('key', 'smoke_enabled')->value('value') === '1';

        // Get news section smoke animation enabled setting
        $newsSmokeEnabled = DB::table('settings')->where('key', 'news_smoke_enabled')->value('value') === '1';

        // Get news section sparks animation enabled setting
        $newsSparksEnabled = DB::table('settings')->where('key', 'news_sparks_enabled')->value('value') === '1';

        // Get server start time for countdown
        $serverStartTime = DB::table('settings')->where('key', 'server_start_time')->value('value');

        // Get hero section logo settings
        $heroUseLogo = DB::table('settings')->where('key', 'hero_use_logo')->value('value') === '1';
        $heroLogoPath = DB::table('settings')->where('key', 'app_logo')->value('value');
        $heroLogoUrl = $heroLogoPath ? asset($heroLogoPath) : null;

        // Get hero logo size (default: 300px)
        $heroLogoSize = (int) (DB::table('settings')->where('key', 'hero_logo_size')->value('value') ?? 300);

        // Get server rates from database
        $serverRates = DB::table('server_rates')->first();
        $expRate = $serverRates->exp_rate ?? 1;
        $doubleDrop = (bool) ($serverRates->double_drop ?? 0);

        return Inertia::render('website/download/index', [
            'serverInfo' => [
                'onlinePlayers' => $onlineData['count'],
                'gmOnline' => $onlineData['gms'] ?? 0,
                'serverTime' => Carbon::now($timezone)->format('H:i:s'),
                'serverDate' => Carbon::now($timezone)->format('d M Y'),
                'timezone' => $timezone,
                'totalAccounts' => $totalAccounts,
                'serverOnline' => $onlineData['serverOnline'] ?? false,
                'appName' => $appName,
                'discordServerId' => $discordServerId,
                'heroBackgroundUrl' => $heroBgPath ? asset($heroBgPath) : null,
                'heroBackgroundWebP' => $heroBgWebP,
                'communityBackgroundUrl' => $communityBgPath ? asset($communityBgPath) : null,
                'newsBackgroundUrl' => $newsBgPath ? asset($newsBgPath) : null,
                'downloadBackgroundUrl' => $downloadBgPath ? asset($downloadBgPath) : null,
                'heroHeight' => (int) (DB::table('settings')->where('key', 'hero_height')->value('value') ?? 40),
                'smokeEnabled' => $smokeEnabled,
                'newsSmokeEnabled' => $newsSmokeEnabled,
                'newsSparksEnabled' => $newsSparksEnabled,
                'appNameColor' => DB::table('settings')->where('key', 'app_name_color')->value('value') ?? '#fbbf24',
                'serverStartTime' => $serverStartTime,
                'heroUseLogo' => $heroUseLogo,
                'heroLogoUrl' => $heroLogoUrl,
                'heroLogoSize' => $heroLogoSize,
                'expRate' => $expRate,
                'doubleDrop' => $doubleDrop,
            ],
            'downloadItems' => $downloadItems,
            'gmList' => $gmList,
            'topSpenders' => $topSpenders,
        ]);
    }

    public function getTopSpendersApi()
    {
        $topSpenders = $this->getTopSpenders(10);

        return response()->json($topSpenders);
    }
}
