import { ChartConfig } from "../types";

/**
 * 쿼리에 안전장치 LIMIT 추가
 */
export function applySafetyLimit(query: string, limit: number = 1000): string {
  const trimmedQuery = query.trim();

  // 이미 LIMIT이 있으면 그대로 반환
  if (/\bLIMIT\b/i.test(trimmedQuery)) {
    return trimmedQuery;
  }

  return `${trimmedQuery} LIMIT ${limit}`;
}

/**
 * 날짜 필터를 쿼리에 적용
 */
export function applyDateFilter(query: string, dateColumn: string, startDate?: string, endDate?: string): string {
  if (!dateColumn || (!startDate && !endDate)) {
    return query;
  }

  const conditions: string[] = [];

  // NULL 값 제외 조건 추가 (필수)
  conditions.push(`${dateColumn} IS NOT NULL`);

  if (startDate) {
    conditions.push(`${dateColumn} >= '${startDate}'`);
  }

  if (endDate) {
    // 종료일은 해당 날짜의 23:59:59까지 포함
    conditions.push(`${dateColumn} <= '${endDate} 23:59:59'`);
  }

  if (conditions.length === 0) {
    return query;
  }

  // FROM 절 이후의 WHERE, GROUP BY, ORDER BY, LIMIT 위치 파악
  // 줄바꿈 제거하여 한 줄로 만들기 (정규식 매칭을 위해)
  let baseQuery = query.trim().replace(/\s+/g, " ");
  let whereClause = "";
  let groupByClause = "";
  let orderByClause = "";
  let limitClause = "";

  // LIMIT 추출
  const limitMatch = baseQuery.match(/\s+LIMIT\s+\d+\s*$/i);
  if (limitMatch) {
    limitClause = limitMatch[0];
    baseQuery = baseQuery.substring(0, limitMatch.index);
  }

  // ORDER BY 추출
  const orderByMatch = baseQuery.match(/\s+ORDER\s+BY\s+.+$/i);
  if (orderByMatch) {
    orderByClause = orderByMatch[0];
    baseQuery = baseQuery.substring(0, orderByMatch.index);
  }

  // GROUP BY 추출
  const groupByMatch = baseQuery.match(/\s+GROUP\s+BY\s+.+$/i);
  if (groupByMatch) {
    groupByClause = groupByMatch[0];
    baseQuery = baseQuery.substring(0, groupByMatch.index);
  }

  // WHERE 추출 (있으면)
  const whereMatch = baseQuery.match(/\s+WHERE\s+.+$/i);
  if (whereMatch) {
    whereClause = whereMatch[0];
    baseQuery = baseQuery.substring(0, whereMatch.index);
  }

  // 날짜 필터 조건 추가
  const filterCondition = conditions.join(" AND ");
  if (whereClause) {
    // 기존 WHERE 절이 있으면 AND로 연결
    whereClause = `${whereClause} AND ${filterCondition}`;
  } else {
    // WHERE 절이 없으면 새로 생성
    whereClause = ` WHERE ${filterCondition}`;
  }

  // 쿼리 재조립
  const finalQuery = `${baseQuery}${whereClause}${groupByClause}${orderByClause}${limitClause}`;
  return finalQuery;
}

/**
 * 빠른 날짜 범위 계산
 */
export function getQuickDateRange(range: "today" | "week" | "month" | "year"): {
  startDate: string;
  endDate: string;
} {
  const now = new Date();
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const fmtDate = (d: Date) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;

  switch (range) {
    case "today":
      return {
        startDate: fmtDate(today),
        endDate: fmtDate(today),
      };

    case "week": {
      const weekStart = new Date(today);
      weekStart.setDate(today.getDate() - today.getDay());
      return {
        startDate: fmtDate(weekStart),
        endDate: fmtDate(today),
      };
    }

    case "month": {
      const monthStart = new Date(today.getFullYear(), today.getMonth(), 1);
      return {
        startDate: fmtDate(monthStart),
        endDate: fmtDate(today),
      };
    }

    case "year": {
      const yearStart = new Date(today.getFullYear(), 0, 1);
      return {
        startDate: fmtDate(yearStart),
        endDate: fmtDate(today),
      };
    }

    default:
      return {
        startDate: "",
        endDate: "",
      };
  }
}

/**
 * 쿼리에서 테이블명 추출
 */
export function extractTableNameFromQuery(query: string): string | null {
  const trimmedQuery = query.trim().toLowerCase();

  // FROM 절 찾기
  const fromMatch = trimmedQuery.match(/\bfrom\s+([a-z_][a-z0-9_]*)/i);
  if (fromMatch) {
    return fromMatch[1];
  }

  return null;
}

/**
 * 날짜 컬럼 자동 감지 (서버에서 테이블 스키마 조회 필요)
 * 이 함수는 쿼리 결과가 아닌, 원본 테이블의 실제 컬럼 타입을 확인해야 합니다.
 *
 * 현재는 임시로 컬럼명 기반 추측만 수행합니다.
 */
export function detectDateColumns(columns: string[], rows: Record<string, any>[]): string[] {
  const dateColumns: string[] = [];

  // 컬럼명 기반 추측 (가장 안전한 방법)
  columns.forEach((col) => {
    const lowerCol = col.toLowerCase();
    if (
      lowerCol.includes("date") ||
      lowerCol.includes("time") ||
      lowerCol.includes("created") ||
      lowerCol.includes("updated") ||
      lowerCol.includes("modified") ||
      lowerCol === "reg_date" ||
      lowerCol === "regdate" ||
      lowerCol === "update_date" ||
      lowerCol === "updatedate" ||
      lowerCol.endsWith("_at") || // created_at, updated_at
      lowerCol.endsWith("_date") || // birth_date, start_date
      lowerCol.endsWith("_time") // start_time, end_time
    ) {
      dateColumns.push(col);
    }
  });

  // 데이터가 있는 경우, 실제 값도 확인 (추가 검증)
  if (rows.length > 0 && dateColumns.length > 0) {
    const firstRow = rows[0];

    // 컬럼명으로 감지된 것들 중에서 실제 날짜 형식인지 재확인
    const validatedColumns = dateColumns.filter((col) => {
      const value = firstRow[col];

      // null이면 스킵 (판단 불가)
      if (value == null) return true;

      // Date 객체면 확실히 날짜
      if (value instanceof Date) return true;

      // 문자열이고 날짜 형식이면 날짜
      if (typeof value === "string") {
        const parsed = Date.parse(value);
        if (!isNaN(parsed)) return true;
      }

      // 숫자면 날짜가 아님 (타임스탬프 제외)
      if (typeof value === "number") {
        // 타임스탬프인지 확인 (1970년 이후의 밀리초 또는 초)
        if (value > 946684800000 || (value > 946684800 && value < 2147483647)) {
          return true;
        }
        return false;
      }

      return false;
    });

    return validatedColumns;
  }

  return dateColumns;
}

/**
 * 쿼리에 필터와 안전장치를 모두 적용
 */
export function applyQueryFilters(query: string, config?: ChartConfig): string {
  let processedQuery = query;

  // 1. 날짜 필터 적용
  if (config?.dateFilter?.enabled && config.dateFilter.dateColumn) {
    processedQuery = applyDateFilter(
      processedQuery,
      config.dateFilter.dateColumn,
      config.dateFilter.startDate,
      config.dateFilter.endDate,
    );
  }

  // 2. 안전장치 LIMIT 적용
  const limit = config?.autoLimit ?? 1000;
  processedQuery = applySafetyLimit(processedQuery, limit);

  return processedQuery;
}
