/**
 * Mandu Guard Analyzer
 *
 * 파일 분석 및 Import 추출
 */

import { safeReadFile } from "../utils/safe-io";
import { dirname, isAbsolute, relative, resolve } from "path";
import { minimatch } from "minimatch";
import type {
  ImportInfo,
  FileAnalysis,
  LayerDefinition,
  GuardConfig,
} from "./types";
import { WATCH_EXTENSIONS } from "./types";

// ═══════════════════════════════════════════════════════════════════════════
// Import Extraction
// ═══════════════════════════════════════════════════════════════════════════

/**
 * Static import 패턴
 *
 * Examples:
 * - import { X } from 'module'
 * - import X from 'module'
 * - import * as X from 'module'
 * - import 'module'
 */
const STATIC_IMPORT_PATTERN = /^import\s+(?:(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)(?:\s*,\s*(?:\{[^}]*\}|\*\s+as\s+\w+|\w+))*)\s+from\s+)?['"]([^'"]+)['"]/gm;

/**
 * Dynamic import 패턴
 *
 * Examples:
 * - import('module')
 * - await import('module')
 */
const DYNAMIC_IMPORT_PATTERN = /(?:await\s+)?import\s*\(\s*['"]([^'"]+)['"]\s*\)/gm;

/**
 * CommonJS require 패턴
 *
 * Examples:
 * - require('module')
 * - const X = require('module')
 */
const REQUIRE_PATTERN = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/gm;

/**
 * Named import 추출 패턴
 */
const NAMED_IMPORT_PATTERN = /\{\s*([^}]+)\s*\}/;

/**
 * Default import 추출 패턴
 */
const DEFAULT_IMPORT_PATTERN = /^import\s+(\w+)/;

/**
 * 파일에서 import 문 추출
 */
export function extractImports(content: string): ImportInfo[] {
  const imports: ImportInfo[] = [];
  const _lines = content.split("\n");

  // Static imports
  let match: RegExpExecArray | null;
  const staticPattern = new RegExp(STATIC_IMPORT_PATTERN.source, "gm");

  while ((match = staticPattern.exec(content)) !== null) {
    const statement = match[0];
    const path = match[1];
    const position = getLineAndColumn(content, match.index);

    // Named imports 추출
    const namedMatch = statement.match(NAMED_IMPORT_PATTERN);
    const namedImports = namedMatch
      ? namedMatch[1].split(",").map((s) => s.trim().split(" as ")[0].trim())
      : undefined;

    // Default import 추출
    const defaultMatch = statement.match(DEFAULT_IMPORT_PATTERN);
    const defaultImport =
      defaultMatch && !statement.includes("{") && !statement.includes("*")
        ? defaultMatch[1]
        : undefined;

    imports.push({
      statement,
      path,
      line: position.line,
      column: position.column,
      type: "static",
      namedImports,
      defaultImport,
    });
  }

  // Dynamic imports
  const dynamicPattern = new RegExp(DYNAMIC_IMPORT_PATTERN.source, "gm");

  while ((match = dynamicPattern.exec(content)) !== null) {
    const position = getLineAndColumn(content, match.index);

    imports.push({
      statement: match[0],
      path: match[1],
      line: position.line,
      column: position.column,
      type: "dynamic",
    });
  }

  // CommonJS requires
  const requirePattern = new RegExp(REQUIRE_PATTERN.source, "gm");

  while ((match = requirePattern.exec(content)) !== null) {
    const position = getLineAndColumn(content, match.index);

    imports.push({
      statement: match[0],
      path: match[1],
      line: position.line,
      column: position.column,
      type: "require",
    });
  }

  return imports;
}

/**
 * 인덱스에서 라인과 컬럼 위치 계산
 */
function getLineAndColumn(content: string, index: number): { line: number; column: number } {
  const lines = content.slice(0, index).split("\n");
  return {
    line: lines.length,
    column: lines[lines.length - 1].length + 1,
  };
}

// ═══════════════════════════════════════════════════════════════════════════
// Layer Resolution
// ═══════════════════════════════════════════════════════════════════════════

/**
 * 파일 경로에서 레이어 결정
 */
export function resolveFileLayer(
  filePath: string,
  layers: LayerDefinition[],
  rootDir: string
): string | null {
  const relativePath = relative(rootDir, filePath).replace(/\\/g, "/");

  for (const layer of layers) {
    if (minimatch(relativePath, layer.pattern)) {
      return layer.name;
    }
  }

  return null;
}

/**
 * Import 경로에서 타겟 레이어 결정
 */
export function resolveImportLayer(
  importPath: string,
  layers: LayerDefinition[],
  srcDir: string,
  fromFile?: string,
  rootDir?: string
): string | null {
  const normalizedImportPath = importPath.replace(/\\/g, "/");
  const normalizedSrcDir = srcDir.replace(/\\/g, "/").replace(/\/$/, "");

  const isAlias = normalizedImportPath.startsWith("@/") || normalizedImportPath.startsWith("~/");
  const isRelative = normalizedImportPath.startsWith(".");
  const isSrcAbsolute = normalizedSrcDir.length > 0 && normalizedSrcDir !== "." &&
    (normalizedImportPath === normalizedSrcDir || normalizedImportPath.startsWith(`${normalizedSrcDir}/`));

  // 상대/alias/src 경로가 아닌 경우 (node_modules 등)
  if (!isAlias && !isRelative && !isSrcAbsolute) {
    return null;
  }

  const candidates: string[] = [];

  if (isAlias) {
    const aliasPath = normalizedImportPath.slice(2);
    const withSrc = normalizedSrcDir.length > 0 ? `${normalizedSrcDir}/${aliasPath}` : aliasPath;
    candidates.push(withSrc, aliasPath);
  } else if (isSrcAbsolute) {
    const trimmed = normalizedSrcDir.length > 0 && normalizedImportPath.startsWith(`${normalizedSrcDir}/`)
      ? normalizedImportPath.slice(normalizedSrcDir.length + 1)
      : normalizedImportPath;
    candidates.push(normalizedImportPath, trimmed);
  } else if (isRelative) {
    if (!fromFile || !rootDir) {
      return null;
    }

    const absoluteFromFile = isAbsolute(fromFile) ? fromFile : resolve(rootDir, fromFile);
    const resolvedPath = resolve(dirname(absoluteFromFile), normalizedImportPath);
    const relativeToRoot = relative(rootDir, resolvedPath).replace(/\\/g, "/");

    // 루트 밖이면 무시
    if (relativeToRoot.startsWith("..") || relativeToRoot.startsWith("../")) {
      return null;
    }

    candidates.push(relativeToRoot);

    if (normalizedSrcDir.length > 0 && relativeToRoot.startsWith(`${normalizedSrcDir}/`)) {
      candidates.push(relativeToRoot.slice(normalizedSrcDir.length + 1));
    }
  }

  for (const candidate of candidates) {
    const normalizedCandidate = candidate.replace(/\\/g, "/");

    for (const layer of layers) {
      if (minimatch(normalizedCandidate, layer.pattern)) {
        return layer.name;
      }
    }
  }

  return null;
}

/**
 * FSD 슬라이스 이름 추출
 */
export function extractSlice(filePath: string, layer: string): string | undefined {
  const relativePath = filePath.replace(/\\/g, "/");

  const marker = `${layer}/`;
  const index = relativePath.indexOf(marker);
  if (index === -1) {
    return undefined;
  }

  const rest = relativePath.slice(index + marker.length);
  const slice = rest.split("/")[0];

  return slice || undefined;
}

// ═══════════════════════════════════════════════════════════════════════════
// File Analysis
// ═══════════════════════════════════════════════════════════════════════════

/**
 * 파일 분석
 */
export async function analyzeFile(
  filePath: string,
  layers: LayerDefinition[],
  rootDir: string
): Promise<FileAnalysis> {
  const result = await safeReadFile(filePath);
  if (!result.ok) {
    throw new Error(`파일 분석 실패: ${filePath} - ${result.error.message}`);
  }

  const content = result.value;
  const imports = extractImports(content);
  const layer = resolveFileLayer(filePath, layers, rootDir);
  const slice = layer ? extractSlice(filePath, layer) : undefined;

  return {
    filePath,
    rootDir,
    layer,
    slice,
    imports,
    analyzedAt: Date.now(),
  };
}

/**
 * 파일이 분석 대상인지 확인
 */
export function shouldAnalyzeFile(
  filePath: string,
  config: GuardConfig,
  rootDir?: string
): boolean {
  const ext = filePath.slice(filePath.lastIndexOf("."));

  // 확장자 체크
  if (!WATCH_EXTENSIONS.includes(ext)) {
    return false;
  }

  // 제외 패턴 체크
  if (config.exclude) {
    const normalizedPath = filePath.replace(/\\/g, "/");
    const candidates = new Set<string>([normalizedPath]);

    if (rootDir) {
      const relativeToRoot = relative(rootDir, filePath).replace(/\\/g, "/");
      candidates.add(relativeToRoot);

      const srcDir = (config.srcDir ?? "src").replace(/\\/g, "/").replace(/\/$/, "");
      if (srcDir && relativeToRoot.startsWith(`${srcDir}/`)) {
        candidates.add(relativeToRoot.slice(srcDir.length + 1));
      }
    }

    for (const pattern of config.exclude) {
      for (const candidate of candidates) {
        if (minimatch(candidate, pattern)) {
          return false;
        }
      }
    }
  }

  return true;
}

/**
 * Import가 무시 대상인지 확인
 */
export function shouldIgnoreImport(
  importPath: string,
  config: GuardConfig
): boolean {
  const normalizedImportPath = importPath.replace(/\\/g, "/");
  const srcDir = (config.srcDir ?? "src").replace(/\\/g, "/").replace(/\/$/, "");
  const isSrcAbsolute = srcDir.length > 0 && srcDir !== "." &&
    (normalizedImportPath === srcDir || normalizedImportPath.startsWith(`${srcDir}/`));

  // 외부 모듈 (node_modules)
  if (
    !normalizedImportPath.startsWith(".") &&
    !normalizedImportPath.startsWith("@/") &&
    !normalizedImportPath.startsWith("~/") &&
    !isSrcAbsolute
  ) {
    return true;
  }

  // 무시 패턴 체크
  if (config.ignoreImports) {
    for (const pattern of config.ignoreImports) {
      if (minimatch(normalizedImportPath, pattern)) {
        return true;
      }
    }
  }

  return false;
}
