import { authenticateLocal, publicUser, signUser } from '../auth.js';
import { loginSchema, passwordChangeSchema, profileSchema, themeSchema } from '../forms/schemas.js';
import { changePassword, updateProfile, updateTheme } from '../models/profileModel.js';
import { findOrProvisionEntraUser } from '../models/userModel.js';
import {
  buildAuthorizeUrl,
  exchangeCodeForToken,
  fetchEntraProfile,
  isEntraLoginConfigured,
  signState,
  verifyState
} from '../services/entraService.js';
import { getSetting } from '../models/settingsModel.js';
import { config } from '../config.js';
import { logger } from '../services/logger.js';

export function login(req, res) {
  const parsed = loginSchema.safeParse(req.body);
  if (!parsed.success) return res.status(400).json({ error: 'Valid email and password are required' });
  const user = authenticateLocal(parsed.data.email, parsed.data.password);
  if (!user) return res.status(401).json({ error: 'Invalid credentials' });
  res.json({ token: signUser(user), user: publicUser(user) });
}

export function me(req, res) {
  res.json({ user: req.user });
}

// Step 1: redirect the browser to the Microsoft sign-in page. 404 when Entra
// login is not fully configured so the client cleanly falls back to local auth.
export function entraLogin(req, res) {
  if (!isEntraLoginConfigured()) return res.status(404).json({ error: 'Entra login is not enabled' });
  const state = signState({ nonce: Date.now() });
  return res.redirect(buildAuthorizeUrl(state));
}

// Step 2: Microsoft redirects back here with an authorization code. We validate
// the signed state, exchange the code, provision the user, and hand the SPA a
// POSHManager JWT via the app URL.
export async function entraCallback(req, res) {
  const appBase = (getSetting('server_fqdn') || config.serverFqdn || '').replace(/\/+$/, '');
  if (!isEntraLoginConfigured()) return res.status(404).json({ error: 'Entra login is not enabled' });
  try {
    if (req.query.error) throw new Error(String(req.query.error_description || req.query.error));
    verifyState(String(req.query.state || ''));
    const tokens = await exchangeCodeForToken(String(req.query.code || ''));
    const profile = await fetchEntraProfile(tokens.access_token);
    const user = findOrProvisionEntraUser(profile);
    const token = signUser(user);
    return res.redirect(`${appBase}/?entraToken=${encodeURIComponent(token)}`);
  } catch (error) {
    logger.error('entra callback failed', { error: error.message });
    return res.redirect(`${appBase}/?entraError=${encodeURIComponent(error.message)}`);
  }
}

export function profile(req, res) {
  const parsed = profileSchema.safeParse(req.body);
  if (!parsed.success) return res.status(400).json({ error: 'Valid profile information is required' });
  try {
    res.json({ user: updateProfile(req.user.id, parsed.data) });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
}

export function theme(req, res) {
  const parsed = themeSchema.safeParse(req.body);
  if (!parsed.success) return res.status(400).json({ error: 'Valid theme id is required' });
  res.json({ user: updateTheme(req.user.id, parsed.data.theme) });
}

export function password(req, res) {
  const parsed = passwordChangeSchema.safeParse(req.body);
  if (!parsed.success) return res.status(400).json({ error: 'New password must be at least 8 characters' });
  try {
    res.json(changePassword(req.user.id, parsed.data));
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
}
