import { App } from "@tinyhttp/app";
import bcrypt from "bcryptjs";
import { JWT_SECRET } from "../config/auth.js";
import { prisma } from "../config/database.js";
import { authMiddleware } from "../middleware/auth.js";
import jwt from "jsonwebtoken";
import fs from "fs/promises";
import passport from "passport";
import { Strategy as GoogleStrategy } from "passport-google-oauth20";

const GOOGLE_CLIENT_ID = process.env["GOOGLE_CLIENT_ID"] || "";
const GOOGLE_CLIENT_SECRET = process.env["GOOGLE_CLIENT_SECRET"] || "";
const GOOGLE_CALLBACK_URL = process.env["GOOGLE_CALLBACK_URL"] || "http://localhost:3000/auth/google/callback";

// Configure Google OAuth Strategy
if (GOOGLE_CLIENT_ID && GOOGLE_CLIENT_SECRET) {
	passport.use(new GoogleStrategy({
		clientID: GOOGLE_CLIENT_ID,
		clientSecret: GOOGLE_CLIENT_SECRET,
		callbackURL: GOOGLE_CALLBACK_URL,
		scope: ["profile", "email"]
	}, async (_accessToken, _refreshToken, profile, done) => {
		try {
			let user = await prisma.user.findFirst({
				where: { googleId: profile.id }
			});

			if (!user) {
				const email = profile.emails?.[0]?.value;
				const name = profile.displayName || profile.emails?.[0]?.value?.split("@")[0] || `user${Date.now()}`;

				user = await prisma.user.create({
					data: {
						googleId: profile.id,
						name,
						email: email ?? null,
						country: "US", // TODO: detect from profile or IP
						droplets: 1000,
						currentCharges: 20,
						maxCharges: 20,
						pixelsPainted: 0,
						level: 1,
						extraColorsBitmap: 0,
						equippedFlag: 0,
						chargesLastUpdatedAt: new Date()
					}
				});
			}

			return done(null, user);
		} catch (error) {
			return done(error as Error, undefined);
		}
	}));
}

export default function (app: App) {
	// Initialize passport
	app.use(passport.initialize() as any);

	// Google OAuth routes
	app.get("/auth/google", (req: any, res: any, next: any) => {
		// Check turnstile token (optional - skip validation if turnstile-disabled)
		const token = req.query.token;
		if (!token) {
			return res.status(400).json({ error: "Token required" });
		}

		// If token is "turnstile-disabled", skip verification (for development)
		if (token === "turnstile-disabled") {
			return passport.authenticate("google", { session: false })(req, res, next);
		}

		// In production, you would verify the turnstile token here
		return passport.authenticate("google", { session: false })(req, res, next);
	});

	app.get("/auth/google/callback",
		passport.authenticate("google", {
			session: false,
			failureRedirect: "/login"
		}),
		async (req: any, res: any) => {
			try {
				const user = req.user;

				if (!user) {
					return res.redirect("/login?error=auth_failed");
				}

				// Create session
				const session = await prisma.session.create({
					data: {
						userId: user.id,
						expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) // 30 days
					}
				});

				// Create JWT token
				const token = jwt.sign(
					{
						userId: user.id,
						sessionId: session.id,
						iss: "FurryPlace",
						exp: Math.floor(session.expiresAt.getTime() / 1000),
						iat: Math.floor(Date.now() / 1000)
					},
					JWT_SECRET
				);

				// Set cookie and redirect
				res.setHeader("Set-Cookie", [
					`j=${token}; HttpOnly; Path=/; Max-Age=${30 * 24 * 60 * 60}; SameSite=Lax`
				]);

				return res.redirect("/");
			} catch (error) {
				console.error("Google callback error:", error);
				return res.redirect("/login?error=server_error");
			}
		}
	);

	app.get("/login", async (_req, res) => {
		const loginHtml = await fs.readFile("./frontend/login.html", "utf8");
		res.setHeader("Content-Type", "text/html");
		return res.send(loginHtml);
	});

	app.post("/login", async (req: any, res: any) => {
		try {
			const { username, password } = req.body;

			if (!username || !password) {
				return res.status(400)
					.json({ error: "Username and password required" });
			}

			let user = await prisma.user.findFirst({
				where: { name: username }
			});

			if (user) {
				const passwordValid = await bcrypt.compare(password, user.passwordHash ?? "");
				if (!passwordValid) {
					return res.status(401)
						.json({ error: "Invalid username or password" });
				}
			} else {
				const passwordHash = await bcrypt.hash(password, 10);

				user = await prisma.user.create({
					data: {
						name: username,
						passwordHash,
						country: "US", // TODO
						droplets: 1000,
						currentCharges: 20,
						maxCharges: 20,
						pixelsPainted: 0,
						level: 1,
						extraColorsBitmap: 0,
						equippedFlag: 0,
						chargesLastUpdatedAt: new Date()
					}
				});
			}

			const session = await prisma.session.create({
				data: {
					userId: user.id,
					expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) // 30 days
				}
			});

			const token = jwt.sign(
				{
					userId: user.id,
					sessionId: session.id,
					iss: "FurryPlace",
					exp: Math.floor(session.expiresAt.getTime() / 1000),
					iat: Math.floor(Date.now() / 1000)
				},
				JWT_SECRET!
			);

			res.setHeader("Set-Cookie", [
				`j=${token}; HttpOnly; Path=/; Max-Age=${30 * 24 * 60 * 60}; SameSite=Lax`
			]);

			return res.json({ success: true });
		} catch (error) {
			console.error("Login error:", error);
			return res.status(500)
				.json({ error: "Internal Server Error" });
		}
	});

	app.post("/auth/logout", authMiddleware, async (req: any, res: any) => {
		try {
			if (req.user?.sessionId) {
				await prisma.session.delete({
					where: { id: req.user.sessionId }
				});
			}

			res.setHeader("Set-Cookie", [
				`j=; HttpOnly; Path=/; Max-Age=0; SameSite=Lax`
			]);

			return res.json({ success: true });
		} catch (error) {
			console.error("Logout error:", error);
			return res.status(500)
				.json({ error: "Internal Server Error" });
		}
	});
}
