// 배치관리 API 클라이언트 (새로운 API로 업데이트)
// 작성일: 2024-12-24

import { apiClient } from "./client";

export type BatchExecutionType = "mapping" | "node_flow";

export interface BatchConfig {
  id?: number;
  batch_name: string;
  description?: string;
  cron_schedule: string;
  is_active?: string;
  company_code?: string;
  save_mode?: 'INSERT' | 'UPSERT';
  conflict_key?: string;
  auth_service_name?: string;
  execution_type?: BatchExecutionType;
  node_flow_id?: number;
  node_flow_context?: Record<string, any>;
  created_date?: Date;
  created_by?: string;
  updated_date?: Date;
  updated_by?: string;
  batch_mappings?: BatchMapping[];
  last_status?: string;
  last_executed_at?: string;
  last_total_records?: number;
}

export interface NodeFlowInfo {
  flow_id: number;
  flow_name: string;
  description?: string;
  company_code?: string;
  node_count: number;
}

export interface BatchStats {
  totalBatches: number;
  activeBatches: number;
  todayExecutions: number;
  todayFailures: number;
  prevDayExecutions: number;
  prevDayFailures: number;
}

export interface SparklineData {
  hour: string;
  success: number;
  failed: number;
}

export interface RecentLog {
  id: number;
  started_at: string;
  finished_at: string | null;
  status: string;
  total_records: number;
  success_records: number;
  failed_records: number;
  error_message: string | null;
  duration_ms: number | null;
}

export interface BatchMapping {
  id?: number;
  batch_config_id?: number;
  
  // FROM 정보
  from_connection_type: 'internal' | 'external';
  from_connection_id?: number;
  from_table_name: string;
  from_column_name: string;
  from_column_type?: string;
  
  // TO 정보
  to_connection_type: 'internal' | 'external';
  to_connection_id?: number;
  to_table_name: string;
  to_column_name: string;
  to_column_type?: string;
  
  mapping_order?: number;
  created_date?: Date;
  created_by?: string;
}

export interface BatchConfigFilter {
  batch_name?: string;
  is_active?: string;
  company_code?: string;
  search?: string;
  page?: number;
  limit?: number;
}

export interface BatchJob {
  id: number;
  job_name: string;
  job_type: string;
  description?: string;
  cron_schedule: string;
  schedule_cron?: string;
  is_active: string;
  last_execution?: Date;
  last_executed_at?: string;
  next_execution?: Date;
  execution_count?: number;
  success_count?: number;
  failure_count?: number;
  status?: string;
  created_date?: Date;
  created_by?: string;
}

export interface ConnectionInfo {
  type: 'internal' | 'external';
  id?: number;
  name: string;
  db_type?: string;
}

export interface ColumnInfo {
  column_name: string;
  data_type: string;
  is_nullable?: boolean;
  column_default?: string;
}

export interface TableInfo {
  table_name: string;
  columns: ColumnInfo[];
  description?: string | null;
}

export interface BatchMappingRequest {
  batchName: string;
  description?: string;
  cronSchedule: string;
  mappings: BatchMapping[];
  isActive?: boolean;
  executionType?: BatchExecutionType;
  nodeFlowId?: number;
  nodeFlowContext?: Record<string, any>;
}

export interface ApiResponse<T> {
  success: boolean;
  data?: T;
  message?: string;
  error?: string;
}

export class BatchAPI {
  private static readonly BASE_PATH = "";

  /**
   * 배치 설정 목록 조회
   */
  static async getBatchConfigs(filter: BatchConfigFilter = {}): Promise<{
    success: boolean;
    data: BatchConfig[];
    pagination?: {
      page: number;
      limit: number;
      total: number;
      totalPages: number;
    };
    message?: string;
  }> {
    try {
      const params = new URLSearchParams();

      if (filter.is_active) params.append("is_active", filter.is_active);
      if (filter.company_code) params.append("company_code", filter.company_code);
      if (filter.search) params.append("search", filter.search);
      if (filter.page) params.append("page", filter.page.toString());
      if (filter.limit) params.append("limit", filter.limit.toString());

      const response = await apiClient.get<{
        success: boolean;
        data: BatchConfig[];
        pagination?: {
          page: number;
          limit: number;
          total: number;
          totalPages: number;
        };
        message?: string;
      }>(`/batch-configs?${params.toString()}`);

      return response.data;
    } catch (error) {
      console.error("배치 설정 목록 조회 오류:", error);
      return {
        success: false,
        data: [],
        message: error instanceof Error ? error.message : "배치 설정 목록 조회에 실패했습니다."
      };
    }
  }

  /**
   * 특정 배치 설정 조회 (별칭)
   */
  static async getBatchConfig(id: number): Promise<BatchConfig> {
    return this.getBatchConfigById(id);
  }

  /**
   * 특정 배치 설정 조회
   */
  static async getBatchConfigById(id: number): Promise<BatchConfig> {
    try {
      const response = await apiClient.get<ApiResponse<BatchConfig>>(
        `/batch-management/batch-configs/${id}`,
      );

      if (!response.data.success) {
        throw new Error(response.data.message || "배치 설정 조회에 실패했습니다.");
      }

      if (!response.data.data) {
        throw new Error("배치 설정을 찾을 수 없습니다.");
      }

      return response.data.data;
    } catch (error) {
      console.error("배치 설정 조회 오류:", error);
      throw error;
    }
  }

  /**
   * 배치 설정 생성
   */
  static async createBatchConfig(data: BatchMappingRequest): Promise<BatchConfig> {
    try {
      const response = await apiClient.post<ApiResponse<BatchConfig>>(
        `/batch-management/batch-configs`,
        data,
      );

      if (!response.data.success) {
        throw new Error(response.data.message || "배치 설정 생성에 실패했습니다.");
      }

      if (!response.data.data) {
        throw new Error("배치 설정 생성 결과를 받을 수 없습니다.");
      }

      return response.data.data;
    } catch (error) {
      console.error("배치 설정 생성 오류:", error);
      throw error;
    }
  }

  /**
   * 배치 설정 수정
   */
  static async updateBatchConfig(
    id: number,
    data: Partial<BatchMappingRequest>
  ): Promise<BatchConfig> {
    try {
      const response = await apiClient.put<ApiResponse<BatchConfig>>(
        `/batch-management/batch-configs/${id}`,
        data,
      );

      if (!response.data.success) {
        throw new Error(response.data.message || "배치 설정 수정에 실패했습니다.");
      }

      if (!response.data.data) {
        throw new Error("배치 설정 수정 결과를 받을 수 없습니다.");
      }

      return response.data.data;
    } catch (error) {
      console.error("배치 설정 수정 오류:", error);
      throw error;
    }
  }

  /**
   * 배치 설정 삭제
   */
  static async deleteBatchConfig(id: number): Promise<void> {
    try {
      const response = await apiClient.delete<ApiResponse<void>>(
        `/batch-configs/${id}`,
      );

      if (!response.data.success) {
        throw new Error(response.data.message || "배치 설정 삭제에 실패했습니다.");
      }
    } catch (error) {
      console.error("배치 설정 삭제 오류:", error);
      throw error;
    }
  }

  /**
   * 사용 가능한 커넥션 목록 조회
   */
  static async getConnections(): Promise<ConnectionInfo[]> {
    try {
      console.log("[BatchAPI] getAvailableConnections 호출 시작");
      console.log("[BatchAPI] API URL:", `/batch-management/connections`);
      
      const response = await apiClient.get<ApiResponse<ConnectionInfo[]>>(
        `/batch-management/connections`,
      );

      console.log("[BatchAPI] API 응답:", response);
      console.log("[BatchAPI] 응답 데이터:", response.data);

      if (!response.data.success) {
        console.error("[BatchAPI] API 응답 실패:", response.data);
        throw new Error(response.data.message || "커넥션 목록 조회에 실패했습니다.");
      }

      const result = response.data.data || [];
      console.log("[BatchAPI] 최종 결과:", result);
      return result;
    } catch (error) {
      console.error("[BatchAPI] 커넥션 목록 조회 오류:", error);
      console.error("[BatchAPI] 오류 상세:", {
        message: error instanceof Error ? error.message : 'Unknown error',
        stack: error instanceof Error ? error.stack : undefined
      });
      throw error;
    }
  }

  /**
   * 특정 커넥션의 테이블 목록 조회
   */
  static async getTablesFromConnection(
    connection: ConnectionInfo
  ): Promise<string[]> {
    try {
      let url = `/batch-management/connections/${connection.type}`;
      if (connection.type === 'external' && connection.id) {
        url += `/${connection.id}`;
      }
      url += '/tables';

      const response = await apiClient.get<ApiResponse<TableInfo[]>>(url);

      if (!response.data.success) {
        throw new Error(response.data.message || "테이블 목록 조회에 실패했습니다.");
      }

      // TableInfo[]에서 table_name만 추출하여 string[]로 변환
      const tables = response.data.data || [];
      return tables.map(table => table.table_name);
    } catch (error) {
      console.error("테이블 목록 조회 오류:", error);
      throw error;
    }
  }

  /**
   * 특정 테이블의 컬럼 정보 조회
   */
  static async getTableColumns(
    connection: ConnectionInfo,
    tableName: string
  ): Promise<ColumnInfo[]> {
    try {
      let url = `/batch-management/connections/${connection.type}`;
      if (connection.type === 'external' && connection.id) {
        url += `/${connection.id}`;
      }
      url += `/tables/${tableName}/columns`;

      const response = await apiClient.get<ApiResponse<ColumnInfo[]>>(url);

      if (!response.data.success) {
        throw new Error(response.data.message || "컬럼 정보 조회에 실패했습니다.");
      }

      return response.data.data || [];
    } catch (error) {
      console.error("컬럼 정보 조회 오류:", error);
      throw error;
    }
  }

  /**
   * 배치 작업 목록 조회
   */
  static async getBatchJobs(): Promise<BatchJob[]> {
    try {
      const response = await apiClient.get<ApiResponse<BatchJob[]>>('/batch-management/jobs');
      
      if (!response.data.success) {
        throw new Error(response.data.message || "배치 작업 목록 조회에 실패했습니다.");
      }

      return response.data.data || [];
    } catch (error) {
      console.error("배치 작업 목록 조회 오류:", error);
      throw error;
    }
  }

  /**
   * 배치 수동 실행
   */
  static async executeBatchConfig(batchId: number): Promise<{
    success: boolean;
    message?: string;
    data?: {
      batchId: string;
      totalRecords: number;
      successRecords: number;
      failedRecords: number;
      duration: number;
    };
  }> {
    try {
      const response = await apiClient.post<{
        success: boolean;
        message?: string;
        data?: {
          batchId: string;
          totalRecords: number;
          successRecords: number;
          failedRecords: number;
          duration: number;
        };
      }>(`/batch-management/batch-configs/${batchId}/execute`);

      return response.data;
    } catch (error) {
      console.error("배치 실행 오류:", error);
      throw error;
    }
  }

  /**
   * 지원되는 배치 작업 타입 조회
   */
  static async getSupportedJobTypes(): Promise<string[]> {
    try {
      const response = await apiClient.get<ApiResponse<string[]>>('/batch-management/job-types');
      if (!response.data.success) {
        throw new Error(response.data.message || "작업 타입 조회에 실패했습니다.");
      }
      return response.data.data || [];
    } catch (error) {
      console.error("작업 타입 조회 오류:", error);
      return [];
    }
  }

  /**
   * 배치 작업 삭제
   */
  static async deleteBatchJob(id: number): Promise<void> {
    try {
      const response = await apiClient.delete<ApiResponse<void>>(`/batch-management/jobs/${id}`);
      if (!response.data.success) {
        throw new Error(response.data.message || "배치 작업 삭제에 실패했습니다.");
      }
    } catch (error) {
      console.error("배치 작업 삭제 오류:", error);
      throw error;
    }
  }

  /**
   * 배치 작업 실행
   */
  static async executeBatchJob(id: number): Promise<void> {
    try {
      const response = await apiClient.post<ApiResponse<void>>(`/batch-management/jobs/${id}/execute`);
      if (!response.data.success) {
        throw new Error(response.data.message || "배치 작업 실행에 실패했습니다.");
      }
    } catch (error) {
      console.error("배치 작업 실행 오류:", error);
      throw error;
    }
  }

  /**
   * auth_tokens 테이블의 서비스명 목록 조회
   */
  static async getAuthServiceNames(): Promise<string[]> {
    try {
      const response = await apiClient.get<{
        success: boolean;
        data: string[];
      }>(`/batch-management/auth-services`);

      if (response.data.success) {
        return response.data.data || [];
      }
      return [];
    } catch (error) {
      console.error("인증 서비스 목록 조회 오류:", error);
      return [];
    }
  }

  /**
   * 노드 플로우 목록 조회 (배치 설정 시 플로우 선택용)
   */
  static async getNodeFlows(): Promise<NodeFlowInfo[]> {
    try {
      const response = await apiClient.get<ApiResponse<NodeFlowInfo[]>>(
        `/batch-management/node-flows`
      );
      if (response.data.success) {
        return response.data.data || [];
      }
      return [];
    } catch (error) {
      console.error("노드 플로우 목록 조회 오류:", error);
      return [];
    }
  }

  /**
   * 배치 대시보드 통계 조회
   */
  static async getBatchStats(): Promise<BatchStats | null> {
    try {
      const response = await apiClient.get<ApiResponse<BatchStats>>(
        `/batch-management/stats`
      );
      if (response.data.success) {
        return response.data.data || null;
      }
      return null;
    } catch (error) {
      console.error("배치 통계 조회 오류:", error);
      return null;
    }
  }

  /**
   * 배치별 최근 24시간 스파크라인 데이터
   */
  static async getBatchSparkline(batchId: number): Promise<SparklineData[]> {
    try {
      const response = await apiClient.get<ApiResponse<SparklineData[]>>(
        `/batch-management/batch-configs/${batchId}/sparkline`
      );
      if (response.data.success) {
        return response.data.data || [];
      }
      return [];
    } catch (error) {
      console.error("스파크라인 조회 오류:", error);
      return [];
    }
  }

  /**
   * 배치별 최근 실행 로그
   */
  static async getBatchRecentLogs(batchId: number, limit: number = 5): Promise<RecentLog[]> {
    try {
      const response = await apiClient.get<ApiResponse<RecentLog[]>>(
        `/batch-management/batch-configs/${batchId}/recent-logs?limit=${limit}`
      );
      if (response.data.success) {
        return response.data.data || [];
      }
      return [];
    } catch (error) {
      console.error("최근 실행 로그 조회 오류:", error);
      return [];
    }
  }
}
