import passport from "passport";
import { Strategy as LocalStrategy } from "passport-local";
import { Express, Request, Response, NextFunction } 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 jwt from "jsonwebtoken";
import cors from "cors";

const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key";
const JWT_EXPIRES_IN = "24h";

declare global {
  namespace Express {
    interface User extends SelectUser {}
    interface Request {
      isAuthenticated(): boolean;
      user?: SelectUser;
    }
  }
}

const scryptAsync = promisify(scrypt);

// Generate JWT token with complete user data
function generateToken(user: SelectUser) {
  return jwt.sign(
    {
      id: user.id,
      username: user.username,
      role: user.role,
      profileImage: user.profileImage,
      name: user.name,
      email: user.email,
      organization: user.organization,
      position: user.position,
    },
    JWT_SECRET,
    { expiresIn: JWT_EXPIRES_IN }
  );
}

// Add isAuthenticated check middleware
function addAuthenticationCheck(req: Request, _res: Response, next: NextFunction) {
  req.isAuthenticated = function() {
    const authHeader = req.headers.authorization;
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      return false;
    }

    try {
      const token = authHeader.split(" ")[1];
      const decoded = jwt.verify(token, JWT_SECRET) as SelectUser;
      req.user = decoded;
      return true;
    } catch (err) {
      console.error("JWT verification failed:", err);
      return false;
    }
  };
  next();
}

// JWT middleware
async function authenticateJWT(req: Request, res: Response, next: NextFunction) {
  const authHeader = req.headers.authorization;
  console.log("Auth header:", authHeader ? "present" : "missing");

  if (authHeader) {
    const token = authHeader.split(" ")[1];
    try {
      const decoded = jwt.verify(token, JWT_SECRET) as SelectUser;
      console.log("JWT verified, user:", decoded.username);

      // Get fresh user data from database
      const user = await storage.getUser(decoded.id);
      if (!user) {
        console.log("User not found in database");
        return res.sendStatus(401);
      }

      req.user = user;
      return next();
    } catch (err) {
      console.error("JWT verification failed:", err);
      return res.sendStatus(401);
    }
  }

  console.log("No JWT token found");
  return res.sendStatus(401);
}

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) {
  try {
    const [hashed, salt] = stored.split(".");
    if (!hashed || !salt) return false;
    const hashedBuf = Buffer.from(hashed, "hex");
    const suppliedBuf = (await scryptAsync(supplied, salt, 64)) as Buffer;
    return timingSafeEqual(hashedBuf, suppliedBuf);
  } catch (err) {
    return false;
  }
}

export function setupAuth(app: Express) {
  app.use(cors({
    origin: true,
    credentials: true,
  }));

  // Add isAuthenticated function to all requests
  app.use(addAuthenticationCheck);

  // Modified login endpoint to use JWT
  app.post("/api/login", async (req, res) => {
    try {
      const { username, password } = req.body;
      console.log("Login attempt for username:", username);

      const user = await storage.getUserByUsername(username);
      if (!user) {
        console.log("User not found");
        return res.status(401).json({ message: "Invalid username or password" });
      }

      const isValid = await comparePasswords(password, user.password);
      if (!isValid) {
        console.log("Invalid password");
        return res.status(401).json({ message: "Invalid username or password" });
      }

      // Generate token and prepare response
      const token = generateToken(user);
      const { password: _, ...userData } = user;

      console.log("Login successful for user:", username);
      res.json({ token, ...userData });
    } catch (error) {
      console.error("Login error:", error);
      res.status(500).json({ message: "Internal server error" });
    }
  });

  // Modified register endpoint
  app.post("/api/register", async (req, res) => {
    try {
      const existingUser = await storage.getUserByUsername(req.body.username);
      if (existingUser) {
        return res.status(400).json({ message: "Username already exists" });
      }

      const hashedPassword = await hashPassword(req.body.password);
      const user = await storage.createUser({
        ...req.body,
        password: hashedPassword,
      });

      // Generate token and prepare response
      const token = generateToken(user);
      const { password: _, ...userData } = user;

      res.status(201).json({ token, ...userData });
    } catch (error) {
      console.error("Registration error:", error);
      res.status(500).json({ message: "Internal server error" });
    }
  });

  // Logout endpoint
  app.post("/api/logout", (_req, res) => {
    res.status(200).json({ message: "Logged out successfully" });
  });

  // Protected user endpoint
  app.get("/api/user", authenticateJWT, (req, res) => {
    const { password: _, ...userData } = req.user!;
    res.json(userData);
  });
}

export { authenticateJWT };