import { auth } from '$lib/auth';
import { error, json } from '@sveltejs/kit';
import { db } from '$lib/server/db';
import { user } from '$lib/server/db/schema';
import { eq } from 'drizzle-orm';
import type { RequestHandler } from './$types';

const TWELVE_HOURS_MS = 12 * 60 * 60 * 1000;
const THIRTY_SIX_HOURS_MS = 36 * 60 * 60 * 1000;

const REWARD_TIERS = [
    1200,   // Day 1
    1500,   // Day 2
    1800,   // Day 3
    2100,   // Day 4
    2500,  // Day 5
    3000,  // Day 6
    3500,  // Day 7
    4000,  // Day 8+
];

function calculateStreak(lastClaim: Date | null, currentStreak: number): number {
    if (!lastClaim) return 1;

    const timeSinceLastClaim = Date.now() - lastClaim.getTime();

    // reset streak if more than 36 hours
    if (timeSinceLastClaim > THIRTY_SIX_HOURS_MS) return 1;

    // only increment if within valid window (12-36 hours)
    if (timeSinceLastClaim >= TWELVE_HOURS_MS) return currentStreak + 1;

    return currentStreak;
}

function calculateReward(streak: number): { total: number; base: number } {
    const tierIndex = Math.min(streak - 1, REWARD_TIERS.length - 1);
    const base = REWARD_TIERS[tierIndex];

    return { total: base, base };
}

export const POST: RequestHandler = async ({ request }) => {
    const session = await auth.api.getSession({ headers: request.headers });
    if (!session?.user) throw error(401, 'Not authenticated');

    const userId = Number(session.user.id);
    const now = new Date();

    return await db.transaction(async (tx) => {
        const userData = await tx.select({
            id: user.id,
            baseCurrencyBalance: user.baseCurrencyBalance,
            lastRewardClaim: user.lastRewardClaim,
            totalRewardsClaimed: user.totalRewardsClaimed,
            loginStreak: user.loginStreak
        })
            .from(user)
            .where(eq(user.id, userId))
            .for('update')
            .limit(1);

        if (!userData[0]) {
            throw error(404, 'User not found');
        }

        const currentUser = userData[0];

        if (currentUser.lastRewardClaim) {
            const timeSinceLastClaim = now.getTime() - currentUser.lastRewardClaim.getTime();
            if (timeSinceLastClaim < TWELVE_HOURS_MS) {
                return json({
                    error: 'Daily reward not yet available',
                    canClaim: false,
                    timeRemaining: TWELVE_HOURS_MS - timeSinceLastClaim
                }, { status: 429 });
            }
        }

        const newStreak = calculateStreak(currentUser.lastRewardClaim, currentUser.loginStreak || 0);
        const reward = calculateReward(newStreak);

        const currentBalance = parseFloat(currentUser.baseCurrencyBalance || '0');
        const currentTotalRewards = parseFloat(currentUser.totalRewardsClaimed || '0');
        const newBalance = currentBalance + reward.total;
        const newTotalRewards = currentTotalRewards + reward.total;

        await tx.update(user)
            .set({
                baseCurrencyBalance: newBalance.toFixed(8),
                lastRewardClaim: now,
                totalRewardsClaimed: newTotalRewards.toFixed(8),
                loginStreak: newStreak
            })
            .where(eq(user.id, currentUser.id));

        return json({
            success: true,
            rewardAmount: reward.total,
            baseReward: reward.base,
            newBalance,
            totalRewardsClaimed: newTotalRewards,
            loginStreak: newStreak,
            nextClaimTime: new Date(now.getTime() + TWELVE_HOURS_MS)
        });
    });
};

export const GET: RequestHandler = async ({ request }) => {
    const session = await auth.api.getSession({ headers: request.headers });
    if (!session?.user) throw error(401, 'Not authenticated');

    const [currentUser] = await db.select({
        id: user.id,
        baseCurrencyBalance: user.baseCurrencyBalance,
        lastRewardClaim: user.lastRewardClaim,
        totalRewardsClaimed: user.totalRewardsClaimed,
        loginStreak: user.loginStreak
    })
        .from(user)
        .where(eq(user.id, Number(session.user.id)))
        .limit(1);

    if (!currentUser) {
        throw error(404, 'User not found');
    }

    const now = new Date();

    let canClaim = true;
    let timeRemaining = 0;
    let nextClaimTime = null;

    if (currentUser.lastRewardClaim) {
        const timeSinceLastClaim = now.getTime() - currentUser.lastRewardClaim.getTime();
        if (timeSinceLastClaim < TWELVE_HOURS_MS) {
            canClaim = false;
            timeRemaining = TWELVE_HOURS_MS - timeSinceLastClaim;
            nextClaimTime = new Date(currentUser.lastRewardClaim.getTime() + TWELVE_HOURS_MS);
        }
    }

    const potentialStreak = calculateStreak(currentUser.lastRewardClaim, currentUser.loginStreak || 0);
    const reward = calculateReward(potentialStreak);

    return json({
        canClaim,
        rewardAmount: reward.total,
        baseReward: reward.base,
        timeRemaining,
        nextClaimTime,
        totalRewardsClaimed: Number(currentUser.totalRewardsClaimed || 0),
        lastRewardClaim: currentUser.lastRewardClaim,
        loginStreak: currentUser.loginStreak || 0
    });
};