/**
 * 권한 체크 미들웨어
 * 3단계 권한 체계 적용: SUPER_ADMIN / COMPANY_ADMIN / USER
 */

import { Request, Response, NextFunction } from "express";
import { PersonBean } from "../types/auth";
import {
  isSuperAdmin,
  isCompanyAdmin,
  isAdmin,
  canExecuteDDL,
  canManageUsers,
  canManageCompanySettings,
  canManageCompanies,
  canAccessCompanyData,
  PermissionLevel,
  createPermissionError,
} from "../utils/permissionUtils";
import { logger } from "../utils/logger";

/**
 * 인증된 요청 타입
 */
export interface AuthenticatedRequest extends Request {
  user?: PersonBean;
}

/**
 * 슈퍼관리자 권한 필수 미들웨어
 */
export const requireSuperAdmin = (
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
): void => {
  try {
    if (!req.user) {
      logger.warn("슈퍼관리자 권한 필요 - 인증되지 않은 사용자", {
        ip: req.ip,
        url: req.originalUrl,
      });

      res.status(401).json({
        success: false,
        error: {
          code: "AUTHENTICATION_REQUIRED",
          details: "인증이 필요합니다.",
        },
      });
      return;
    }

    if (!isSuperAdmin(req.user)) {
      logger.warn("슈퍼관리자 권한 부족", {
        userId: req.user.userId,
        companyCode: req.user.companyCode,
        userType: req.user.userType,
        ip: req.ip,
        url: req.originalUrl,
      });

      res.status(403).json(createPermissionError(PermissionLevel.SUPER_ADMIN));
      return;
    }

    logger.info("슈퍼관리자 권한 확인 완료", {
      userId: req.user.userId,
      url: req.originalUrl,
    });

    next();
  } catch (error) {
    logger.error("슈퍼관리자 권한 확인 중 오류:", error);
    res.status(500).json({
      success: false,
      error: {
        code: "AUTHORIZATION_ERROR",
        details: "권한 확인 중 오류가 발생했습니다.",
      },
    });
  }
};

/**
 * 관리자 권한 필수 미들웨어 (슈퍼관리자 + 회사관리자)
 */
export const requireAdmin = (
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
): void => {
  try {
    if (!req.user) {
      res.status(401).json({
        success: false,
        error: {
          code: "AUTHENTICATION_REQUIRED",
          details: "인증이 필요합니다.",
        },
      });
      return;
    }

    if (!isAdmin(req.user)) {
      logger.warn("관리자 권한 부족", {
        userId: req.user.userId,
        userType: req.user.userType,
        companyCode: req.user.companyCode,
        ip: req.ip,
        url: req.originalUrl,
      });

      res
        .status(403)
        .json(createPermissionError(PermissionLevel.COMPANY_ADMIN));
      return;
    }

    logger.info("관리자 권한 확인 완료", {
      userId: req.user.userId,
      userType: req.user.userType,
      url: req.originalUrl,
    });

    next();
  } catch (error) {
    logger.error("관리자 권한 확인 중 오류:", error);
    res.status(500).json({
      success: false,
      error: {
        code: "AUTHORIZATION_ERROR",
        details: "권한 확인 중 오류가 발생했습니다.",
      },
    });
  }
};

/**
 * 회사 데이터 접근 권한 체크 미들웨어
 * req.params.companyCode 또는 req.query.companyCode 확인
 */
export const requireCompanyAccess = (
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
): void => {
  try {
    if (!req.user) {
      res.status(401).json({
        success: false,
        error: {
          code: "AUTHENTICATION_REQUIRED",
          details: "인증이 필요합니다.",
        },
      });
      return;
    }

    const targetCompanyCode =
      (req.params.companyCode as string) ||
      (req.query.companyCode as string) ||
      (req.body.companyCode as string);

    if (!targetCompanyCode) {
      res.status(400).json({
        success: false,
        error: {
          code: "COMPANY_CODE_REQUIRED",
          details: "회사 코드가 필요합니다.",
        },
      });
      return;
    }

    if (!canAccessCompanyData(req.user, targetCompanyCode)) {
      logger.warn("회사 데이터 접근 권한 없음", {
        userId: req.user.userId,
        userCompanyCode: req.user.companyCode,
        targetCompanyCode,
        ip: req.ip,
        url: req.originalUrl,
      });

      res.status(403).json({
        success: false,
        error: {
          code: "COMPANY_ACCESS_DENIED",
          details: "해당 회사의 데이터에 접근할 권한이 없습니다.",
        },
      });
      return;
    }

    next();
  } catch (error) {
    logger.error("회사 데이터 접근 권한 확인 중 오류:", error);
    res.status(500).json({
      success: false,
      error: {
        code: "AUTHORIZATION_ERROR",
        details: "권한 확인 중 오류가 발생했습니다.",
      },
    });
  }
};

/**
 * 사용자 관리 권한 체크 미들웨어
 */
export const requireUserManagement = (
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
): void => {
  try {
    if (!req.user) {
      res.status(401).json({
        success: false,
        error: {
          code: "AUTHENTICATION_REQUIRED",
          details: "인증이 필요합니다.",
        },
      });
      return;
    }

    const targetCompanyCode =
      (req.params.companyCode as string) ||
      (req.query.companyCode as string) ||
      (req.body.companyCode as string);

    if (!canManageUsers(req.user, targetCompanyCode)) {
      logger.warn("사용자 관리 권한 없음", {
        userId: req.user.userId,
        userCompanyCode: req.user.companyCode,
        targetCompanyCode,
        ip: req.ip,
        url: req.originalUrl,
      });

      res.status(403).json({
        success: false,
        error: {
          code: "USER_MANAGEMENT_DENIED",
          details: "사용자 관리 권한이 없습니다.",
        },
      });
      return;
    }

    next();
  } catch (error) {
    logger.error("사용자 관리 권한 확인 중 오류:", error);
    res.status(500).json({
      success: false,
      error: {
        code: "AUTHORIZATION_ERROR",
        details: "권한 확인 중 오류가 발생했습니다.",
      },
    });
  }
};

/**
 * 회사 설정 변경 권한 체크 미들웨어
 */
export const requireCompanySettingsManagement = (
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
): void => {
  try {
    if (!req.user) {
      res.status(401).json({
        success: false,
        error: {
          code: "AUTHENTICATION_REQUIRED",
          details: "인증이 필요합니다.",
        },
      });
      return;
    }

    const targetCompanyCode =
      (req.params.companyCode as string) ||
      (req.query.companyCode as string) ||
      (req.body.companyCode as string);

    if (!canManageCompanySettings(req.user, targetCompanyCode)) {
      logger.warn("회사 설정 변경 권한 없음", {
        userId: req.user.userId,
        userCompanyCode: req.user.companyCode,
        targetCompanyCode,
        ip: req.ip,
        url: req.originalUrl,
      });

      res.status(403).json({
        success: false,
        error: {
          code: "COMPANY_SETTINGS_DENIED",
          details: "회사 설정 변경 권한이 없습니다.",
        },
      });
      return;
    }

    next();
  } catch (error) {
    logger.error("회사 설정 변경 권한 확인 중 오류:", error);
    res.status(500).json({
      success: false,
      error: {
        code: "AUTHORIZATION_ERROR",
        details: "권한 확인 중 오류가 발생했습니다.",
      },
    });
  }
};

/**
 * 회사 생성/삭제 권한 체크 미들웨어 (슈퍼관리자 전용)
 */
export const requireCompanyManagement = (
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
): void => {
  try {
    if (!req.user) {
      res.status(401).json({
        success: false,
        error: {
          code: "AUTHENTICATION_REQUIRED",
          details: "인증이 필요합니다.",
        },
      });
      return;
    }

    if (!canManageCompanies(req.user)) {
      logger.warn("회사 관리 권한 없음", {
        userId: req.user.userId,
        userType: req.user.userType,
        companyCode: req.user.companyCode,
        ip: req.ip,
        url: req.originalUrl,
      });

      res.status(403).json({
        success: false,
        error: {
          code: "COMPANY_MANAGEMENT_DENIED",
          details: "회사 생성/삭제는 최고 관리자만 가능합니다.",
        },
      });
      return;
    }

    next();
  } catch (error) {
    logger.error("회사 관리 권한 확인 중 오류:", error);
    res.status(500).json({
      success: false,
      error: {
        code: "AUTHORIZATION_ERROR",
        details: "권한 확인 중 오류가 발생했습니다.",
      },
    });
  }
};

/**
 * DDL 실행 권한 체크 미들웨어 (슈퍼관리자 전용)
 */
export const requireDDLPermission = (
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
): void => {
  try {
    if (!req.user) {
      res.status(401).json({
        success: false,
        error: {
          code: "AUTHENTICATION_REQUIRED",
          details: "인증이 필요합니다.",
        },
      });
      return;
    }

    if (!canExecuteDDL(req.user)) {
      logger.warn("DDL 실행 권한 없음", {
        userId: req.user.userId,
        userType: req.user.userType,
        companyCode: req.user.companyCode,
        ip: req.ip,
        url: req.originalUrl,
      });

      res.status(403).json({
        success: false,
        error: {
          code: "DDL_EXECUTION_DENIED",
          details:
            "DDL 실행은 최고 관리자만 가능합니다. 데이터베이스 스키마 변경은 company_code가 '*'이고 user_type이 'SUPER_ADMIN'인 사용자만 수행할 수 있습니다.",
        },
      });
      return;
    }

    logger.info("DDL 실행 권한 확인 완료", {
      userId: req.user.userId,
      url: req.originalUrl,
    });

    next();
  } catch (error) {
    logger.error("DDL 실행 권한 확인 중 오류:", error);
    res.status(500).json({
      success: false,
      error: {
        code: "AUTHORIZATION_ERROR",
        details: "권한 확인 중 오류가 발생했습니다.",
      },
    });
  }
};
