import {
    TextChannel,
    ContainerBuilder,
    TextDisplayBuilder,
    SectionBuilder,
    SeparatorBuilder,
    ThumbnailBuilder,
    MessageFlags,
    SeparatorSpacingSize
} from "discord.js";
import { AuroraClient } from "@/lib/BotClient";
import { DrizzleClient } from "@shared/db/DrizzleClient";
import { users, transactions, lootdrops, inventory } from "@db/schema";
import { desc, sql } from "drizzle-orm";
import { getGuildConfig, invalidateGuildConfigCache } from "@shared/lib/config";
import { guildSettingsService } from "@shared/modules/guild-settings/guild-settings.service";
import { env } from "@shared/lib/env";

const COLORS = {
    HEADER: 0x9B59B6,
    LEADERS: 0xF1C40F,
    ACTIVITY: 0x3498DB,
    ALERT: 0xE74C3C
};

function getPrimaryGuildId(): string | null {
    return env.DISCORD_GUILD_ID ?? null;
}

export const terminalService = {
    init: async (channel: TextChannel) => {
        const guildId = channel.guildId;
        if (!guildId) {
            console.error("Cannot initialize terminal: no guild ID");
            return;
        }

        // Clean up old terminal if exists
        const currentConfig = await getGuildConfig(guildId);
        if (currentConfig.terminal?.channelId && currentConfig.terminal?.messageId) {
            try {
                const oldChannel = await AuroraClient.channels.fetch(currentConfig.terminal.channelId).catch(() => null) as TextChannel | null;
                if (oldChannel) {
                    const oldMsg = await oldChannel.messages.fetch(currentConfig.terminal.messageId).catch(() => null);
                    if (oldMsg) await oldMsg.delete();
                }
            } catch (e) {
                // Ignore if old message doesn't exist
            }
        }

        const msg = await channel.send({ content: "🔄 Initializing Aurora Station..." });

        // Save to database
        await guildSettingsService.upsertSettings({
            guildId,
            terminalChannelId: channel.id,
            terminalMessageId: msg.id,
        });
        invalidateGuildConfigCache(guildId);

        await terminalService.update(guildId);
    },

    update: async (guildId?: string) => {
        const effectiveGuildId = guildId ?? getPrimaryGuildId();
        if (!effectiveGuildId) {
            console.warn("No guild ID available for terminal update");
            return;
        }

        const guildConfig = await getGuildConfig(effectiveGuildId);

        if (!guildConfig.terminal?.channelId || !guildConfig.terminal?.messageId) {
            return;
        }

        try {
            const channel = await AuroraClient.channels.fetch(guildConfig.terminal.channelId).catch(() => null) as TextChannel | null;
            if (!channel) {
                console.warn("Terminal channel not found");
                return;
            }
            const message = await channel.messages.fetch(guildConfig.terminal.messageId).catch(() => null);
            if (!message) {
                console.warn("Terminal message not found");
                return;
            }

            const containers = await terminalService.buildMessage();

            await message.edit({
                content: null,
                embeds: null as any,
                components: containers as any,
                flags: MessageFlags.IsComponentsV2,
                allowedMentions: { parse: [] }
            });

        } catch (error) {
            console.error("Failed to update terminal:", error);
        }
    },

    buildMessage: async () => {
        // ═══════════════════════════════════════════════════════════
        // DATA FETCHING
        // ═══════════════════════════════════════════════════════════

        const allUsers = await DrizzleClient.select().from(users);
        const totalUsers = allUsers.length;
        const totalWealth = allUsers.reduce((acc: bigint, u: any) => acc + (u.balance || 0n), 0n);

        // System stats
        const uptime = process.uptime();
        const uptimeHours = Math.floor(uptime / 3600);
        const uptimeMinutes = Math.floor((uptime % 3600) / 60);
        const ping = AuroraClient.ws.ping;
        const now = Math.floor(Date.now() / 1000);

        // Guild member count (if available)
        const guild = AuroraClient.guilds.cache.first();
        const memberCount = guild?.memberCount ?? totalUsers;

        // Additional metrics
        const avgLevel = totalUsers > 0
            ? Math.round(allUsers.reduce((acc: number, u: any) => acc + (u.level || 1), 0) / totalUsers)
            : 1;
        const topStreak = allUsers.reduce((max: number, u: any) => Math.max(max, u.dailyStreak || 0), 0);

        // Items in circulation
        const itemsResult = await DrizzleClient
            .select({ total: sql<string>`COALESCE(SUM(${inventory.quantity}), 0)` })
            .from(inventory);
        const totalItems = Number(itemsResult[0]?.total || 0);

        // Last command timestamp
        const lastCmd = AuroraClient.lastCommandTimestamp
            ? `<t:${Math.floor(AuroraClient.lastCommandTimestamp / 1000)}:R>`
            : "*Never*";

        // Leaderboards
        const topLevels = [...allUsers]
            .sort((a, b) => (b.level || 0) - (a.level || 0))
            .slice(0, 3);
        const topWealth = [...allUsers]
            .sort((a, b) => Number(b.balance || 0n) - Number(a.balance || 0n))
            .slice(0, 3);

        // Lootdrops
        const activeDrops = await DrizzleClient.query.lootdrops.findMany({
            where: (lootdrops: any, { isNull }: any) => isNull(lootdrops.claimedBy),
            limit: 1,
            orderBy: desc(lootdrops.createdAt)
        });

        const recentDrops = await DrizzleClient.query.lootdrops.findMany({
            where: (lootdrops: any, { isNotNull }: any) => isNotNull(lootdrops.claimedBy),
            limit: 1,
            orderBy: desc(lootdrops.createdAt)
        });

        // Recent transactions
        const recentTx = await DrizzleClient.query.transactions.findMany({
            limit: 3,
            orderBy: [desc(transactions.createdAt)]
        });

        // ═══════════════════════════════════════════════════════════
        // HELPER FORMATTERS
        // ═══════════════════════════════════════════════════════════

        const getMedal = (i: number) => i === 0 ? "🥇" : i === 1 ? "🥈" : "🥉";

        const formatLeaderEntry = (u: typeof users.$inferSelect, i: number, type: 'level' | 'wealth') => {
            const medal = getMedal(i);
            const value = type === 'level'
                ? `Lvl ${u.level ?? 1}`
                : `${Number(u.balance ?? 0).toLocaleString()} AU`;
            return `${medal} **${u.username}** — ${value}`;
        };

        const getActivityIcon = (type: string) => {
            if (type.includes("LOOT")) return "🌠";
            if (type.includes("GIFT")) return "🎁";
            if (type.includes("SHOP")) return "🛒";
            if (type.includes("DAILY")) return "☀️";
            if (type.includes("QUEST")) return "📜";
            return "💫";
        };

        // ═══════════════════════════════════════════════════════════
        // CONTAINER 1: HEADER - Station Overview
        // ═══════════════════════════════════════════════════════════

        const botAvatar = AuroraClient.user?.displayAvatarURL({ size: 64 }) ?? "";

        const headerSection = new SectionBuilder()
            .addTextDisplayComponents(
                new TextDisplayBuilder().setContent("# 🔮 AURORA STATION"),
                new TextDisplayBuilder().setContent("-# Real-time server observatory")
            )
            .setThumbnailAccessory(
                new ThumbnailBuilder().setURL(botAvatar)
            );

        const statsText = [
            `📡 **Uptime** ${uptimeHours}h ${uptimeMinutes}m`,
            `🏓 **Ping** ${ping}ms`,
            `👥 **Students** ${totalUsers}`,
            `🪙 **Economy** ${totalWealth.toLocaleString()} AU`
        ].join("  •  ");

        const secondaryStats = [
            `📦 **Items** ${totalItems.toLocaleString()}`,
            `📈 **Avg Lvl** ${avgLevel}`,
            `🔥 **Top Streak** ${topStreak}d`,
            `⚡ **Last Cmd** ${lastCmd}`
        ].join("  •  ");

        const headerContainer = new ContainerBuilder()
            .setAccentColor(COLORS.HEADER)
            .addSectionComponents(headerSection)
            .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small))
            .addTextDisplayComponents(
                new TextDisplayBuilder().setContent(statsText),
                new TextDisplayBuilder().setContent(secondaryStats),
                new TextDisplayBuilder().setContent(`-# Updated <t:${now}:R>`)
            );

        // ═══════════════════════════════════════════════════════════
        // CONTAINER 2: LEADERBOARDS
        // ═══════════════════════════════════════════════════════════

        const levelLeaderText = topLevels.length > 0
            ? topLevels.map((u, i) => formatLeaderEntry(u, i, 'level')).join("\n")
            : "*No data yet*";

        const wealthLeaderText = topWealth.length > 0
            ? topWealth.map((u, i) => formatLeaderEntry(u, i, 'wealth')).join("\n")
            : "*No data yet*";

        const leadersContainer = new ContainerBuilder()
            .setAccentColor(COLORS.LEADERS)
            .addTextDisplayComponents(
                new TextDisplayBuilder().setContent("## ✨ CONSTELLATION LEADERS")
            )
            .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small))
            .addTextDisplayComponents(
                new TextDisplayBuilder().setContent(`**Brightest Stars**\n${levelLeaderText}`),
                new TextDisplayBuilder().setContent(`**Gilded Nebulas**\n${wealthLeaderText}`)
            );

        // ═══════════════════════════════════════════════════════════
        // CONTAINER 3: LIVE ACTIVITY
        // ═══════════════════════════════════════════════════════════

        // Determine if there's an active lootdrop
        const hasActiveDrop = activeDrops.length > 0 && activeDrops[0];
        const activityColor = hasActiveDrop ? COLORS.ALERT : COLORS.ACTIVITY;

        const activityContainer = new ContainerBuilder()
            .setAccentColor(activityColor)
            .addTextDisplayComponents(
                new TextDisplayBuilder().setContent("## 🌠 LIVE ACTIVITY")
            )
            .addSeparatorComponents(new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small));

        // Active lootdrop or recent event
        if (hasActiveDrop) {
            const drop = activeDrops[0]!;
            const expiresTimestamp = Math.floor(drop.expiresAt!.getTime() / 1000);

            activityContainer.addTextDisplayComponents(
                new TextDisplayBuilder().setContent(
                    `🚨 **SHOOTING STAR ACTIVE**\n` +
                    `> **Reward:** \`${drop.rewardAmount} ${drop.currency}\`\n` +
                    `> **Location:** <#${drop.channelId}>\n` +
                    `> **Expires:** <t:${expiresTimestamp}:R>`
                )
            );
        } else if (recentDrops.length > 0 && recentDrops[0]) {
            const drop = recentDrops[0];
            const claimer = allUsers.find((u: any) => u.id === drop.claimedBy);
            const claimedTimestamp = drop.createdAt ? Math.floor(drop.createdAt.getTime() / 1000) : now;

            activityContainer.addTextDisplayComponents(
                new TextDisplayBuilder().setContent(
                    `✅ **Last Star Claimed**\n` +
                    `> **${claimer?.username ?? 'Unknown'}** collected \`${drop.rewardAmount} ${drop.currency}\` <t:${claimedTimestamp}:R>`
                )
            );
        } else {
            activityContainer.addTextDisplayComponents(
                new TextDisplayBuilder().setContent(`-# The sky is quiet... waiting for the next star.`)
            );
        }

        // Recent transactions
        if (recentTx.length > 0) {
            activityContainer.addSeparatorComponents(
                new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Small)
            );

            const txLines = recentTx.map((tx: any) => {
                const time = Math.floor(tx.createdAt!.getTime() / 1000);
                const icon = getActivityIcon(tx.type);
                const user = allUsers.find((u: any) => u.id === tx.userId);

                // Clean description (remove trailing channel IDs)
                let desc = tx.description || "Unknown";
                desc = desc.replace(/\s*\d{17,19}\s*$/, "").trim();

                return `${icon} **${user?.username ?? 'Unknown'}**: ${desc} · <t:${time}:R>`;
            });

            activityContainer.addTextDisplayComponents(
                new TextDisplayBuilder().setContent("**Recent Echoes**"),
                new TextDisplayBuilder().setContent(txLines.join("\n"))
            );
        }

        return [headerContainer, leadersContainer, activityContainer];
    }
};
