import passport from "passport";
import { Strategy as LocalStrategy } from "passport-local";
import { Express } from "express";
import session from "express-session";
import { scrypt, randomBytes, timingSafeEqual } from "crypto";
import { promisify } from "util";
import { storage } from "./storage";
import { User as SelectUser } from "@shared/schema";
import 'dotenv/config';

declare global {
	namespace Express {
		interface User extends SelectUser { }
	}
}

const scryptAsync = promisify(scrypt);

export async function hashPassword(password: string) {
	const salt = randomBytes(16).toString("hex");
	const buf = (await scryptAsync(password, salt, 64)) as Buffer;
	return `${buf.toString("hex")}.${salt}`;
}

async function comparePasswords(supplied: string, stored: string) {
	const [hashed, salt] = stored.split(".");
	const hashedBuf = Buffer.from(hashed, "hex");
	const suppliedBuf = (await scryptAsync(supplied, salt, 64)) as Buffer;
	return timingSafeEqual(hashedBuf, suppliedBuf);
}

export function setupAuth(app: Express) {
	const sessionSettings: session.SessionOptions = {
		secret: process.env.REPL_ID!,
		resave: false,
		saveUninitialized: false,
		store: storage.sessionStore,
	};

	if (app.get("env") === "production") {
		app.set("trust proxy", 1);
	}

	app.use(session(sessionSettings));
	app.use(passport.initialize());
	app.use(passport.session());

	passport.use(
		new LocalStrategy(async (username, password, done) => {
			const user = await storage.getUserByUsername(username);
			if (!user || !(await comparePasswords(password, user.password))) {
				return done(null, false);
			}

			// Check if user status is active
			if (!user.status) {
				console.log(`Login denied for user ${username}: user account is disabled`);
				return done(null, false);
			}

			// Check if user belongs to an inactive subsidiary (skip for mhc_admin and supervisor)
			if (user.subsidiaryId && user.role !== "mhc_admin" && user.role !== "supervisor") {
				const subsidiary = await storage.getSubsidiary(user.subsidiaryId);
				if (!subsidiary || !subsidiary.status) {
					console.log(`Login denied for user ${username}: subsidiary is inactive`);
					return done(null, false);
				}
			}

			return done(null, user);
		}),
	);

	passport.serializeUser((user, done) => done(null, user.id));
	passport.deserializeUser(async (id: number, done) => {
		const user = await storage.getUser(id);

		// Check if user status is still active
		if (user && !user.status) {
			console.log(`Session invalidated for user ${user.username}: user account is disabled`);
			return done(null, false);
		}

		// Check if user's subsidiary is still active (for existing sessions, skip for mhc_admin and supervisor)
		if (user && user.subsidiaryId && user.role !== "mhc_admin" && user.role !== "supervisor") {
			const subsidiary = await storage.getSubsidiary(user.subsidiaryId);
			if (!subsidiary || !subsidiary.status) {
				console.log(`Session invalidated for user ${user.username}: subsidiary is inactive`);
				return done(null, false);
			}
		}

		done(null, user);
	});

app.post("/api/register", async (req, res) => {
	const existingUser = await storage.getUserByUsername(req.body.username);
	if (existingUser) {
		return res.status(400).send("Username already exists");
	}

	const user = await storage.createUser({
		...req.body,
		password: await hashPassword(req.body.password),
	});

	res.status(201).json(user); // Just return success — no login
});


	app.post("/api/login", async (req, res, next) => {
		// Add more detailed logging
		console.log("Login attempt for username:", req.body.username);

		// Check if the user exists and their status before authentication
		const user = await storage.getUserByUsername(req.body.username);
		if (user) {
			// Check user status
			if (!user.status) {
				console.log(`Login denied for user ${req.body.username}: user account is disabled`);
				return res.status(403).json({
					message: "Access denied. Your account has been disabled. Please contact your administrator."
				});
			}

			// Check subsidiary status
			if (user.subsidiaryId) {
				const subsidiary = await storage.getSubsidiary(user.subsidiaryId);
				if (!subsidiary || !subsidiary.status) {
					console.log(`Login denied for user ${req.body.username}: subsidiary is inactive`);
					return res.status(403).json({
						message: "Access denied. Your subsidiary account has been deactivated. Please contact your administrator."
					});
				}
			}
		}

		passport.authenticate("local", (err: any, user: Express.User, info: any) => {
			if (err) {
				console.error("Login error:", err);
				return next(err);
			}

			if (!user) {
				console.log("Login failed: Invalid credentials");
				return res.status(401).json({ message: "Invalid username or password" });
			}

			req.login(user, (loginErr) => {
				if (loginErr) {
					console.error("Session error:", loginErr);
					return next(loginErr);
				}

				console.log("Login successful for user:", user.username);
				return res.status(200).json(user);
			});
		})(req, res, next);
	});

	app.post("/api/logout", (req, res, next) => {
		req.logout((err) => {
			if (err) return next(err);
			res.sendStatus(200);
		});
	});

	app.get("/api/user", (req, res) => {
		if (!req.isAuthenticated()) return res.sendStatus(401);
		res.json(req.user);
	});
}

