/**
 * SSO Auth Controller
 *
 * 로그인, 토큰 검증/갱신, 사용자 CRUD
 */

const jwt = require('jsonwebtoken');
const userModel = require('../models/userModel');
const redis = require('../utils/redis');

const JWT_SECRET = process.env.SSO_JWT_SECRET;
const JWT_EXPIRES_IN = process.env.SSO_JWT_EXPIRES_IN || '7d';
const JWT_REFRESH_SECRET = process.env.SSO_JWT_REFRESH_SECRET;
const JWT_REFRESH_EXPIRES_IN = process.env.SSO_JWT_REFRESH_EXPIRES_IN || '30d';

const MAX_LOGIN_ATTEMPTS = 5;
const LOGIN_LOCKOUT_SECONDS = 300; // 5분

/**
 * JWT 토큰 페이로드 생성 (모든 시스템 공통 구조)
 */
function createTokenPayload(user) {
  return {
    user_id: user.user_id,
    id: user.user_id,
    username: user.username,
    name: user.name,
    department_id: user.department_id || null,
    department_name: user.department_name || user.department || null,
    is_production: user.is_production || false,
    department: user.department,
    role: user.role,
    access_level: user.role,
    sub: user.username,
    partner_company_id: user.partner_company_id || null,
    system_access: {
      system1: user.system1_access,
      system2: user.system2_access,
      system3: user.system3_access
    }
  };
}

/**
 * POST /api/auth/login
 */
async function login(req, res, next) {
  try {
    const { username, password } = req.body;

    if (!username || !password) {
      return res.status(400).json({ success: false, error: '사용자명과 비밀번호를 입력하세요' });
    }

    // 로그인 시도 횟수 확인
    const attemptKey = `login_attempts:${username}`;
    const attempts = parseInt(await redis.get(attemptKey)) || 0;
    if (attempts >= MAX_LOGIN_ATTEMPTS) {
      return res.status(429).json({ success: false, error: '로그인 시도 횟수를 초과했습니다. 5분 후 다시 시도하세요' });
    }

    const user = await userModel.findByUsername(username);
    if (!user) {
      await redis.incr(attemptKey);
      await redis.expire(attemptKey, LOGIN_LOCKOUT_SECONDS);
      return res.status(401).json({ success: false, error: '사용자명 또는 비밀번호가 올바르지 않습니다' });
    }

    // 협력업체 계정 만료일 체크
    if (user.account_expires_at && new Date(user.account_expires_at) < new Date()) {
      return res.status(401).json({ success: false, error: '계정이 만료되었습니다. 관리자에게 문의하세요.' });
    }

    const valid = await userModel.verifyPassword(password, user.password_hash);
    if (!valid) {
      await redis.incr(attemptKey);
      await redis.expire(attemptKey, LOGIN_LOCKOUT_SECONDS);
      return res.status(401).json({ success: false, error: '사용자명 또는 비밀번호가 올바르지 않습니다' });
    }

    // 로그인 성공 시 시도 횟수 초기화
    await redis.del(attemptKey);
    await userModel.updateLastLogin(user.user_id);

    const payload = createTokenPayload(user);
    const access_token = jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
    const refresh_token = jwt.sign(
      { user_id: user.user_id, type: 'refresh' },
      JWT_REFRESH_SECRET,
      { expiresIn: JWT_REFRESH_EXPIRES_IN }
    );

    // SSO 쿠키는 클라이언트(login.html)에서 domain=.technicalkorea.net으로 설정
    // 서버 httpOnly 쿠키는 서브도메인 공유 불가하므로 제거

    res.json({
      success: true,
      access_token,
      refresh_token,
      token_type: 'bearer',
      user: {
        user_id: user.user_id,
        username: user.username,
        name: user.name,
        department: user.department,
        department_id: user.department_id || null,
        department_name: user.department_name || user.department || null,
        is_production: user.is_production || false,
        role: user.role,
        system_access: payload.system_access
      }
    });
  } catch (err) {
    next(err);
  }
}

/**
 * POST /api/auth/login/form - OAuth2 form data login (M-Project 호환)
 */
async function loginForm(req, res, next) {
  try {
    const username = req.body.username;
    const password = req.body.password;

    if (!username || !password) {
      return res.status(400).json({ detail: 'Missing username or password' });
    }

    // Rate limiting (동일 로직: /login과 공유)
    const attemptKey = `login_attempts:${username}`;
    const attempts = parseInt(await redis.get(attemptKey)) || 0;
    if (attempts >= MAX_LOGIN_ATTEMPTS) {
      return res.status(429).json({ detail: '로그인 시도 횟수를 초과했습니다. 5분 후 다시 시도하세요' });
    }

    const user = await userModel.findByUsername(username);
    if (!user) {
      await redis.incr(attemptKey);
      await redis.expire(attemptKey, LOGIN_LOCKOUT_SECONDS);
      return res.status(401).json({ detail: 'Incorrect username or password' });
    }

    // 협력업체 계정 만료일 체크
    if (user.account_expires_at && new Date(user.account_expires_at) < new Date()) {
      return res.status(401).json({ detail: '계정이 만료되었습니다' });
    }

    const valid = await userModel.verifyPassword(password, user.password_hash);
    if (!valid) {
      await redis.incr(attemptKey);
      await redis.expire(attemptKey, LOGIN_LOCKOUT_SECONDS);
      return res.status(401).json({ detail: 'Incorrect username or password' });
    }

    // 로그인 성공 시 시도 횟수 초기화
    await redis.del(attemptKey);

    await userModel.updateLastLogin(user.user_id);

    const payload = createTokenPayload(user);
    const access_token = jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });

    res.json({
      access_token,
      token_type: 'bearer',
      user: {
        id: user.user_id,
        username: user.username,
        full_name: user.name,
        role: user.role,
        department: user.department
      }
    });
  } catch (err) {
    next(err);
  }
}

/**
 * GET /api/auth/validate
 */
async function validate(req, res, next) {
  try {
    const token = extractToken(req);
    if (!token) {
      return res.status(401).json({ success: false, error: '토큰이 필요합니다' });
    }

    const decoded = jwt.verify(token, JWT_SECRET);
    const user = await userModel.findById(decoded.user_id || decoded.id);
    if (!user || !user.is_active) {
      return res.status(401).json({ success: false, error: '유효하지 않은 사용자입니다' });
    }

    res.json({
      success: true,
      user: {
        user_id: user.user_id,
        username: user.username,
        name: user.name,
        department: user.department,
        department_id: user.department_id || null,
        department_name: user.department_name || user.department || null,
        is_production: user.is_production || false,
        role: user.role,
        system_access: {
          system1: user.system1_access,
          system2: user.system2_access,
          system3: user.system3_access
        }
      }
    });
  } catch (err) {
    if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
      return res.status(401).json({ success: false, error: '유효하지 않은 토큰입니다' });
    }
    next(err);
  }
}

/**
 * GET /api/auth/me - 현재 사용자 정보 (M-Project 호환)
 */
async function me(req, res, next) {
  try {
    const token = extractToken(req);
    if (!token) {
      return res.status(401).json({ detail: 'Not authenticated' });
    }

    const decoded = jwt.verify(token, JWT_SECRET);
    const user = await userModel.findById(decoded.user_id || decoded.id);
    if (!user || !user.is_active) {
      return res.status(401).json({ detail: 'User not found or inactive' });
    }

    res.json({
      id: user.user_id,
      username: user.username,
      full_name: user.name,
      role: user.role,
      department: user.department,
      is_active: user.is_active
    });
  } catch (err) {
    if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
      return res.status(401).json({ detail: 'Could not validate credentials' });
    }
    next(err);
  }
}

/**
 * POST /api/auth/refresh
 */
async function refresh(req, res, next) {
  try {
    const { refresh_token } = req.body;
    if (!refresh_token) {
      return res.status(400).json({ success: false, error: 'Refresh 토큰이 필요합니다' });
    }

    const decoded = jwt.verify(refresh_token, JWT_REFRESH_SECRET);
    if (decoded.type !== 'refresh') {
      return res.status(401).json({ success: false, error: '유효하지 않은 Refresh 토큰입니다' });
    }

    const user = await userModel.findById(decoded.user_id);
    if (!user || !user.is_active) {
      return res.status(401).json({ success: false, error: '유효하지 않은 사용자입니다' });
    }

    const payload = createTokenPayload(user);
    const access_token = jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
    const new_refresh_token = jwt.sign(
      { user_id: user.user_id, type: 'refresh' },
      JWT_REFRESH_SECRET,
      { expiresIn: JWT_REFRESH_EXPIRES_IN }
    );

    res.json({
      success: true,
      access_token,
      refresh_token: new_refresh_token,
      token_type: 'bearer'
    });
  } catch (err) {
    if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
      return res.status(401).json({ success: false, error: '유효하지 않은 Refresh 토큰입니다' });
    }
    next(err);
  }
}

/**
 * POST /api/auth/logout
 */
async function logout(req, res) {
  res.clearCookie('sso_token', { path: '/' });
  res.json({ success: true, message: '로그아웃 되었습니다' });
}

/**
 * GET /api/auth/users - 모든 사용자 목록
 */
async function getUsers(req, res, next) {
  try {
    const users = await userModel.findAll();
    res.json({ success: true, data: users });
  } catch (err) {
    next(err);
  }
}

/**
 * POST /api/auth/users - 사용자 생성
 */
async function createUser(req, res, next) {
  try {
    const { username, password, name, department, role } = req.body;

    if (!username || !password) {
      return res.status(400).json({ success: false, error: '사용자명과 비밀번호는 필수입니다' });
    }

    const existing = await userModel.findByUsername(username);
    if (existing) {
      return res.status(409).json({ success: false, error: '이미 존재하는 사용자명입니다' });
    }

    const user = await userModel.create({ username, password, name, department, role });
    res.status(201).json({ success: true, data: user });
  } catch (err) {
    next(err);
  }
}

/**
 * PUT /api/auth/users/:id - 사용자 수정
 */
async function updateUser(req, res, next) {
  try {
    const userId = parseInt(req.params.id);
    const user = await userModel.update(userId, req.body);
    if (!user) {
      return res.status(404).json({ success: false, error: '사용자를 찾을 수 없습니다' });
    }
    res.json({ success: true, data: user });
  } catch (err) {
    next(err);
  }
}

/**
 * DELETE /api/auth/users/:id - 사용자 비활성화
 */
async function deleteUser(req, res, next) {
  try {
    const userId = parseInt(req.params.id);
    await userModel.deleteUser(userId);
    res.json({ success: true, message: '사용자가 비활성화되었습니다' });
  } catch (err) {
    next(err);
  }
}

/**
 * Bearer 토큰 또는 쿠키에서 토큰 추출
 */
function extractToken(req) {
  // Authorization header (SSO 토큰은 항상 Bearer로 전달)
  const authHeader = req.headers['authorization'];
  if (authHeader && authHeader.startsWith('Bearer ')) {
    return authHeader.split(' ')[1];
  }
  return null;
}

module.exports = {
  login,
  loginForm,
  validate,
  me,
  refresh,
  logout,
  getUsers,
  createUser,
  updateUser,
  deleteUser
};
