/**
 * POP 공통 SQL 빌더
 *
 * DataSourceConfig를 SQL 문자열로 변환하는 순수 유틸리티.
 * 원본: pop-dashboard/utils/dataFetcher.ts에서 추출 (로직 동일).
 *
 * 대시보드(dataFetcher.ts)는 기존 코드를 그대로 유지하고,
 * 새 컴포넌트(useDataSource 등)는 이 파일을 사용한다.
 * 향후 대시보드 교체 시 dataFetcher.ts가 이 파일을 import하도록 변경 예정.
 *
 * 보안:
 * - escapeSQL: SQL 인젝션 방지 (문자열 이스케이프)
 * - sanitizeIdentifier: 테이블명/컬럼명에서 위험 문자 제거
 */

import type { DataSourceConfig, DataSourceFilter } from "@/lib/registry/pop-components/types";

// ===== SQL 값 이스케이프 =====

/** SQL 문자열 값 이스케이프 (SQL 인젝션 방지) */
function escapeSQL(value: unknown): string {
  if (value === null || value === undefined) return "NULL";
  if (typeof value === "number") return String(value);
  if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
  // 문자열: 작은따옴표 이스케이프
  const str = String(value).replace(/'/g, "''");
  return `'${str}'`;
}

// ===== 식별자 검증 (테이블명, 컬럼명) =====

/** SQL 식별자(테이블명, 컬럼명)에서 위험한 문자 제거 */
function sanitizeIdentifier(name: string): string {
  // 알파벳, 숫자, 언더스코어, 점(스키마.테이블)만 허용
  return name.replace(/[^a-zA-Z0-9_.]/g, "");
}

// ===== 설정 완료 여부 검증 =====

/**
 * DataSourceConfig의 필수값이 모두 채워졌는지 검증
 * 설정 중간 상태(테이블 미선택, 컬럼 미선택 등)에서는
 * SQL을 생성하지 않도록 사전 차단
 *
 * @returns null이면 유효, 문자열이면 미완료 사유
 */
export function validateDataSourceConfig(config: DataSourceConfig): string | null {
  // 테이블명 필수
  if (!config.tableName || !config.tableName.trim()) {
    return "테이블이 선택되지 않았습니다";
  }

  // 집계 함수가 설정되었으면 대상 컬럼도 필수
  // (단, COUNT는 컬럼 없이도 COUNT(*)로 처리 가능)
  if (config.aggregation) {
    const aggType = config.aggregation.type?.toLowerCase();
    const aggCol = config.aggregation.column?.trim();
    if (aggType !== "count" && !aggCol) {
      return `${config.aggregation.type.toUpperCase()} 집계에 대상 컬럼이 필요합니다`;
    }
  }

  // 조인이 있으면 조인 조건 필수
  if (config.joins?.length) {
    for (const join of config.joins) {
      if (!join.targetTable?.trim()) {
        return "조인 대상 테이블이 선택되지 않았습니다";
      }
      if (!join.on.sourceColumn?.trim() || !join.on.targetColumn?.trim()) {
        return "조인 조건 컬럼이 설정되지 않았습니다";
      }
    }
  }

  return null;
}

// ===== 필터 조건 SQL 생성 =====

/** DataSourceFilter 배열을 WHERE 절 조건문으로 변환 */
function buildWhereClause(filters: DataSourceFilter[]): string {
  // 컬럼명이 빈 필터는 무시 (설정 중간 상태 방어)
  const validFilters = filters.filter((f) => f.column?.trim());
  if (!validFilters.length) return "";

  const conditions = validFilters.map((f) => {
    const col = sanitizeIdentifier(f.column);

    switch (f.operator) {
      case "between": {
        const arr = Array.isArray(f.value) ? f.value : [f.value, f.value];
        return `${col} BETWEEN ${escapeSQL(arr[0])} AND ${escapeSQL(arr[1])}`;
      }
      case "in": {
        const arr = Array.isArray(f.value) ? f.value : [f.value];
        const vals = arr.map(escapeSQL).join(", ");
        return `${col} IN (${vals})`;
      }
      case "like":
        return `${col} LIKE ${escapeSQL(f.value)}`;
      default:
        return `${col} ${f.operator} ${escapeSQL(f.value)}`;
    }
  });

  return `WHERE ${conditions.join(" AND ")}`;
}

// ===== 집계 SQL 빌더 =====

/**
 * DataSourceConfig를 SELECT SQL로 변환
 *
 * @param config - 데이터 소스 설정
 * @returns SQL 문자열
 */
export function buildAggregationSQL(config: DataSourceConfig): string {
  const tableName = sanitizeIdentifier(config.tableName);

  // SELECT 절
  let selectClause: string;
  if (config.aggregation) {
    const aggType = config.aggregation.type.toUpperCase();
    const aggCol = config.aggregation.column?.trim()
      ? sanitizeIdentifier(config.aggregation.column)
      : "";

    // COUNT는 컬럼 없으면 COUNT(*), 나머지는 컬럼 필수
    if (!aggCol) {
      selectClause = aggType === "COUNT"
        ? "COUNT(*) as value"
        : `${aggType}(${tableName}.*) as value`;
    } else {
      selectClause = `${aggType}(${aggCol}) as value`;
    }

    // GROUP BY가 있으면 해당 컬럼도 SELECT에 포함
    if (config.aggregation.groupBy?.length) {
      const groupCols = config.aggregation.groupBy.map(sanitizeIdentifier).join(", ");
      selectClause = `${groupCols}, ${selectClause}`;
    }
  } else {
    selectClause = "*";
  }

  // FROM 절 (조인 포함 - 조건이 완전한 조인만 적용)
  let fromClause = tableName;
  if (config.joins?.length) {
    for (const join of config.joins) {
      // 조인 설정이 불완전하면 건너뜀 (설정 중간 상태 방어)
      if (!join.targetTable?.trim() || !join.on.sourceColumn?.trim() || !join.on.targetColumn?.trim()) {
        continue;
      }
      const joinTable = sanitizeIdentifier(join.targetTable);
      const joinType = join.joinType.toUpperCase();
      const srcCol = sanitizeIdentifier(join.on.sourceColumn);
      const tgtCol = sanitizeIdentifier(join.on.targetColumn);
      fromClause += ` ${joinType} JOIN ${joinTable} ON ${tableName}.${srcCol} = ${joinTable}.${tgtCol}`;
    }
  }

  // WHERE 절
  const whereClause = config.filters?.length
    ? buildWhereClause(config.filters)
    : "";

  // GROUP BY 절
  let groupByClause = "";
  if (config.aggregation?.groupBy?.length) {
    groupByClause = `GROUP BY ${config.aggregation.groupBy.map(sanitizeIdentifier).join(", ")}`;
  }

  // ORDER BY 절
  let orderByClause = "";
  if (config.sort?.length) {
    const sortCols = config.sort
      .map((s) => `${sanitizeIdentifier(s.column)} ${s.direction.toUpperCase()}`)
      .join(", ");
    orderByClause = `ORDER BY ${sortCols}`;
  }

  // LIMIT 절
  const limitClause = config.limit ? `LIMIT ${Math.max(1, Math.floor(config.limit))}` : "";

  return [
    `SELECT ${selectClause}`,
    `FROM ${fromClause}`,
    whereClause,
    groupByClause,
    orderByClause,
    limitClause,
  ]
    .filter(Boolean)
    .join(" ");
}
