const express = require("express");
const router = express.Router();
const crypto = require("crypto");
const { encryptMsToken } = require("../utils/msTokenCrypto");

const stateStore = new Map();

const MICROSOFT_CLIENT_ID = process.env.MICROSOFT_CLIENT_ID;
const MICROSOFT_CLIENT_SECRET = process.env.MICROSOFT_CLIENT_SECRET;
const FRONTEND_URL = process.env.FRONTEND_URL || "http://localhost:5173";
const BACKEND_URL = process.env.BACKEND_URL || "http://localhost:3000";
const REDIRECT_URI =
  process.env.MICROSOFT_REDIRECT_URI || `${BACKEND_URL}/api/auth/microsoft/callback`;

const { MICROSOFT_SCOPES } = require("../services/microsoftGraph");

function parseIdTokenPayload(idToken) {
  if (!idToken || typeof idToken !== "string") return {};
  const parts = idToken.split(".");
  if (parts.length < 2) return {};
  try {
    const json = Buffer.from(parts[1], "base64url").toString("utf8");
    return JSON.parse(json);
  } catch {
    return {};
  }
}

/**
 * GET /api/auth/microsoft/login
 */
router.get("/login", (req, res) => {
  if (!MICROSOFT_CLIENT_ID || !MICROSOFT_CLIENT_SECRET) {
    console.error("Microsoft OAuth: MICROSOFT_CLIENT_ID / MICROSOFT_CLIENT_SECRET not configured");
    return res.redirect(
      `${FRONTEND_URL}/auth/login?error=${encodeURIComponent("Microsoft login is not configured on this server")}`,
    );
  }

  const state = crypto.randomBytes(16).toString("hex");
  stateStore.set(state, { timestamp: Date.now() });

  for (const [key, value] of stateStore.entries()) {
    if (Date.now() - value.timestamp > 10 * 60 * 1000) {
      stateStore.delete(key);
    }
  }

  // Use tenant-specific endpoint for single-tenant apps
  // For Nordsafe tenant: 8fe3321f-727d-4c35-a7f7-452493485284
  const tenantId = process.env.MICROSOFT_TENANT_ID || "8fe3321f-727d-4c35-a7f7-452493485284";
  const authUrl = new URL(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`);
  authUrl.searchParams.append("client_id", MICROSOFT_CLIENT_ID);
  authUrl.searchParams.append("response_type", "code");
  authUrl.searchParams.append("redirect_uri", REDIRECT_URI);
  authUrl.searchParams.append("response_mode", "query");
  authUrl.searchParams.append("scope", MICROSOFT_SCOPES);
  authUrl.searchParams.append("state", state);

  console.log("🔍 Redirecting to Microsoft login:", authUrl.toString());
  res.redirect(authUrl.toString());
});

/**
 * GET /api/auth/microsoft/callback
 */
router.get("/callback", async (req, res) => {
  const { code, state, error, error_description } = req.query;

  if (error) {
    console.error("❌ Microsoft OAuth error:", error, error_description);
    return res.redirect(`${FRONTEND_URL}/auth/login?error=${encodeURIComponent(error_description || error)}`);
  }

  if (!state || !stateStore.has(state)) {
    console.error("❌ Invalid state parameter");
    return res.redirect(`${FRONTEND_URL}/auth/login?error=invalid_state`);
  }

  stateStore.delete(state);

  if (!code) {
    console.error("❌ No authorization code received");
    return res.redirect(`${FRONTEND_URL}/auth/login?error=no_code`);
  }

  if (!MICROSOFT_CLIENT_ID || !MICROSOFT_CLIENT_SECRET) {
    return res.redirect(
      `${FRONTEND_URL}/auth/login?error=${encodeURIComponent("Microsoft login is not configured on this server")}`,
    );
  }

  try {
    console.log("📤 Exchanging code for tokens...");
    
    // Use tenant-specific endpoint for single-tenant apps
    const tenantId = process.env.MICROSOFT_TENANT_ID || "8fe3321f-727d-4c35-a7f7-452493485284";
    const tokenResponse = await fetch(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
      body: new URLSearchParams({
        client_id: MICROSOFT_CLIENT_ID,
        client_secret: MICROSOFT_CLIENT_SECRET,
        code: code,
        redirect_uri: REDIRECT_URI,
        grant_type: "authorization_code",
        scope: MICROSOFT_SCOPES,
      }),
    });

    const tokens = await tokenResponse.json();

    if (!tokenResponse.ok) {
      console.error("❌ Token exchange failed:", tokens);
      return res.redirect(`${FRONTEND_URL}/auth/login?error=token_exchange_failed`);
    }

    console.log("✅ Tokens received");

    const userResponse = await fetch("https://graph.microsoft.com/v1.0/me", {
      headers: {
        Authorization: `Bearer ${tokens.access_token}`,
      },
    });

    const userInfo = await userResponse.json();
    console.log("✅ User info received:", userInfo.mail || userInfo.userPrincipalName);

    const { Users, Companies, UserProjects, Projects } = require("../models");
    const { sign } = require("jsonwebtoken");

    const email = userInfo.mail || userInfo.userPrincipalName;
    const name = userInfo.displayName;
    const microsoftId = userInfo.id;

    const idClaims = parseIdTokenPayload(tokens.id_token);
    const userTenantId = idClaims.tid || null;

    let user = await Users.findOne({
      where: { email },
      include: [Companies],
    });

    if (!user) {
      console.log("📝 Creating new user...");
      const company = await Companies.create({
        name: `${name}'s Company`,
        subscriptionType: "trial",
        subscriptionEndsAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
      });

      user = await Users.create({
        email,
        fullname: name,
        password: crypto.randomBytes(32).toString("hex"),
        role: "admin",
        CompanyId: company.id,
        microsoftId,
      });

      user = await Users.findByPk(user.id, {
        include: [Companies],
      });
    } else {
      if (!user.microsoftId) {
        await Users.update({ microsoftId }, { where: { id: user.id } });
      }
    }

    const expiresIn = tokens.expires_in || 3600;
    const msTokenExpiresAt = new Date(Date.now() + expiresIn * 1000);
    const encAccess = encryptMsToken(tokens.access_token);
    const encRefresh = tokens.refresh_token ? encryptMsToken(tokens.refresh_token) : null;

    await Companies.update(
      {
        tenantId: userTenantId,
        msAccessToken: encAccess,
        msRefreshToken: encRefresh,
        msTokenExpiresAt,
      },
      { where: { id: user.CompanyId } },
    );

    // Trigger SharePoint setup in background and store result
    setImmediate(async () => {
      try {
        const { setupCompanySharepoint } = require("../services/sharepoint");
        const result = await setupCompanySharepoint(user.CompanyId, tokens.access_token);
        
        if (result.success) {
          console.log(`✅ SharePoint setup completed for company ${user.CompanyId}`);
          if (result.createdLists && result.createdLists.length > 0) {
            console.log(`   Created ${result.createdLists.length} lists:`, result.createdLists.join(', '));
          }
          if (result.missingLists && result.missingLists.length > 0) {
            console.log(`   ⚠️  ${result.missingLists.length} lists need manual creation:`, result.missingLists.join(', '));
          }
        } else {
          console.error(`❌ SharePoint setup failed for company ${user.CompanyId}:`, result.error);
        }
      } catch (err) {
        console.error("SharePoint setup (background):", err.message);
      }
    });

    user = await Users.findByPk(user.id, {
      include: [Companies],
    });

    const projects = await UserProjects.findAll({
      where: { UserId: user.id },
      include: Projects,
    });

    const token = sign(
      {
        companyName: user.Company.name,
        role: user.role,
        id: user.id,
        email: user.email,
        fullname: user.fullname,
        companyId: user.CompanyId,
        subscriptionEndsAt: user.Company.subscriptionEndsAt,
        subscriptionType: user.Company.subscriptionType,
      },
      process.env.JWT_SECRET,
    );

    console.log("✅ Authentication successful, redirecting to frontend...");

    const redirectUrl = new URL("/auth/microsoft/success", FRONTEND_URL);
    redirectUrl.searchParams.append("token", token);
    if (projects.length > 0) {
      redirectUrl.searchParams.append(
        "project",
        JSON.stringify({
          name: projects[0].Project.name,
          id: projects[0].Project.id,
        }),
      );
    }

    res.redirect(redirectUrl.toString());
  } catch (error) {
    console.error("❌ Error during Microsoft authentication:", error);
    res.redirect(`${FRONTEND_URL}/auth/login?error=authentication_failed`);
  }
});

module.exports = router;
