import { query, queryOne, transaction } from "../database/db";

export interface ComponentStandardData {
  component_code: string;
  component_name: string;
  component_name_eng?: string;
  description?: string;
  category: string;
  icon_name?: string;
  default_size?: any;
  component_config: any;
  preview_image?: string;
  sort_order?: number;
  is_active?: string;
  is_public?: string;
  company_code: string;
  created_by?: string;
  updated_by?: string;
}

export interface ComponentQueryParams {
  category?: string;
  active?: string;
  is_public?: string;
  company_code?: string;
  search?: string;
  sort?: string;
  order?: "asc" | "desc";
  limit?: number;
  offset?: number;
}

class ComponentStandardService {
  /**
   * 컴포넌트 목록 조회
   */
  async getComponents(params: ComponentQueryParams = {}) {
    const {
      category,
      active = "Y",
      is_public,
      company_code,
      search,
      sort = "sort_order",
      order = "asc",
      limit,
      offset = 0,
    } = params;

    const whereConditions: string[] = [];
    const values: any[] = [];
    let paramIndex = 1;

    // 활성화 상태 필터
    if (active) {
      whereConditions.push(`is_active = $${paramIndex++}`);
      values.push(active);
    }

    // 카테고리 필터
    if (category && category !== "all") {
      whereConditions.push(`category = $${paramIndex++}`);
      values.push(category);
    }

    // 공개 여부 필터
    if (is_public) {
      whereConditions.push(`is_public = $${paramIndex++}`);
      values.push(is_public);
    }

    // 회사별 필터 (공개 컴포넌트 + 해당 회사 컴포넌트)
    if (company_code) {
      whereConditions.push(
        `(is_public = 'Y' OR company_code = $${paramIndex++})`
      );
      values.push(company_code);
    }

    // 검색 조건
    if (search) {
      whereConditions.push(
        `(component_name ILIKE $${paramIndex} OR component_name_eng ILIKE $${paramIndex} OR description ILIKE $${paramIndex})`
      );
      values.push(`%${search}%`);
      paramIndex++;
    }

    const whereClause =
      whereConditions.length > 0
        ? `WHERE ${whereConditions.join(" AND ")}`
        : "";

    // 정렬 컬럼 검증 (SQL 인젝션 방지)
    const validSortColumns = [
      "sort_order",
      "component_name",
      "category",
      "created_date",
      "updated_date",
    ];
    const sortColumn = validSortColumns.includes(sort) ? sort : "sort_order";
    const sortOrder = order === "desc" ? "DESC" : "ASC";

    // 컴포넌트 조회
    const components = await query<any>(
      `SELECT * FROM component_standards
       ${whereClause}
       ORDER BY ${sortColumn} ${sortOrder}
       ${limit ? `LIMIT $${paramIndex++}` : ""}
       ${limit ? `OFFSET $${paramIndex++}` : ""}`,
      limit ? [...values, limit, offset] : values
    );

    // 전체 개수 조회
    const countResult = await queryOne<{ count: string }>(
      `SELECT COUNT(*) as count FROM component_standards ${whereClause}`,
      values
    );

    const total = parseInt(countResult?.count || "0");

    return {
      components,
      total,
      limit,
      offset,
    };
  }

  /**
   * 컴포넌트 상세 조회
   */
  async getComponent(component_code: string) {
    const component = await queryOne<any>(
      `SELECT * FROM component_standards WHERE component_code = $1`,
      [component_code]
    );

    if (!component) {
      throw new Error(`컴포넌트를 찾을 수 없습니다: ${component_code}`);
    }

    return component;
  }

  /**
   * 컴포넌트 생성
   */
  async createComponent(data: ComponentStandardData) {
    // 중복 코드 확인
    const existing = await queryOne<any>(
      `SELECT * FROM component_standards WHERE component_code = $1`,
      [data.component_code]
    );

    if (existing) {
      throw new Error(
        `이미 존재하는 컴포넌트 코드입니다: ${data.component_code}`
      );
    }

    // 'active' 필드를 'is_active'로 변환
    const createData = { ...data };
    if ("active" in createData) {
      createData.is_active = (createData as any).active;
      delete (createData as any).active;
    }

    const component = await queryOne<any>(
      `INSERT INTO component_standards 
       (component_code, component_name, component_name_eng, description, category, 
        icon_name, default_size, component_config, preview_image, sort_order, 
        is_active, is_public, company_code, created_by, updated_by, created_date, updated_date)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, NOW(), NOW())
       RETURNING *`,
      [
        createData.component_code,
        createData.component_name,
        createData.component_name_eng || null,
        createData.description || null,
        createData.category,
        createData.icon_name || null,
        createData.default_size || null,
        createData.component_config,
        createData.preview_image || null,
        createData.sort_order || 0,
        createData.is_active || "Y",
        createData.is_public || "N",
        createData.company_code,
        createData.created_by || null,
        createData.updated_by || null,
      ]
    );

    return component;
  }

  /**
   * 컴포넌트 수정
   */
  async updateComponent(
    component_code: string,
    data: Partial<ComponentStandardData>
  ) {
    const existing = await this.getComponent(component_code);

    // 'active' 필드를 'is_active'로 변환
    const updateData = { ...data };
    if ("active" in updateData) {
      updateData.is_active = (updateData as any).active;
      delete (updateData as any).active;
    }

    // 동적 UPDATE 쿼리 생성
    const updateFields: string[] = ["updated_date = NOW()"];
    const values: any[] = [];
    let paramIndex = 1;

    const fieldMapping: { [key: string]: string } = {
      component_name: "component_name",
      component_name_eng: "component_name_eng",
      description: "description",
      category: "category",
      icon_name: "icon_name",
      default_size: "default_size",
      component_config: "component_config",
      preview_image: "preview_image",
      sort_order: "sort_order",
      is_active: "is_active",
      is_public: "is_public",
      company_code: "company_code",
      updated_by: "updated_by",
    };

    for (const [key, dbField] of Object.entries(fieldMapping)) {
      if (key in updateData) {
        updateFields.push(`${dbField} = $${paramIndex++}`);
        values.push((updateData as any)[key]);
      }
    }

    const component = await queryOne<any>(
      `UPDATE component_standards 
       SET ${updateFields.join(", ")}
       WHERE component_code = $${paramIndex}
       RETURNING *`,
      [...values, component_code]
    );

    return component;
  }

  /**
   * 컴포넌트 삭제
   */
  async deleteComponent(component_code: string) {
    const existing = await this.getComponent(component_code);

    await query(`DELETE FROM component_standards WHERE component_code = $1`, [
      component_code,
    ]);

    return { message: `컴포넌트가 삭제되었습니다: ${component_code}` };
  }

  /**
   * 컴포넌트 정렬 순서 업데이트
   */
  async updateSortOrder(
    updates: Array<{ component_code: string; sort_order: number }>
  ) {
    await transaction(async (client) => {
      for (const { component_code, sort_order } of updates) {
        await client.query(
          `UPDATE component_standards 
           SET sort_order = $1, updated_date = NOW()
           WHERE component_code = $2`,
          [sort_order, component_code]
        );
      }
    });

    return { message: "정렬 순서가 업데이트되었습니다." };
  }

  /**
   * 컴포넌트 복제
   */
  async duplicateComponent(
    source_code: string,
    new_code: string,
    new_name: string
  ) {
    const source = await this.getComponent(source_code);

    // 새 코드 중복 확인
    const existing = await queryOne<any>(
      `SELECT * FROM component_standards WHERE component_code = $1`,
      [new_code]
    );

    if (existing) {
      throw new Error(`이미 존재하는 컴포넌트 코드입니다: ${new_code}`);
    }

    const component = await queryOne<any>(
      `INSERT INTO component_standards 
       (component_code, component_name, component_name_eng, description, category, 
        icon_name, default_size, component_config, preview_image, sort_order, 
        is_active, is_public, company_code, created_date, updated_date)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, NOW(), NOW())
       RETURNING *`,
      [
        new_code,
        new_name,
        source?.component_name_eng,
        source?.description,
        source?.category,
        source?.icon_name,
        source?.default_size,
        source?.component_config,
        source?.preview_image,
        source?.sort_order,
        source?.is_active,
        source?.is_public,
        source?.company_code || "DEFAULT",
      ]
    );

    return component;
  }

  /**
   * 카테고리 목록 조회
   */
  async getCategories(company_code?: string) {
    const whereConditions: string[] = ["is_active = 'Y'"];
    const values: any[] = [];

    if (company_code) {
      whereConditions.push(`(is_public = 'Y' OR company_code = $1)`);
      values.push(company_code);
    }

    const whereClause = `WHERE ${whereConditions.join(" AND ")}`;

    const categories = await query<{ category: string }>(
      `SELECT DISTINCT category FROM component_standards ${whereClause} ORDER BY category`,
      values
    );

    return categories
      .map((item) => item.category)
      .filter((category) => category !== null);
  }

  /**
   * 컴포넌트 통계
   */
  async getStatistics(company_code?: string) {
    const whereConditions: string[] = ["is_active = 'Y'"];
    const values: any[] = [];

    if (company_code) {
      whereConditions.push(`(is_public = 'Y' OR company_code = $1)`);
      values.push(company_code);
    }

    const whereClause = `WHERE ${whereConditions.join(" AND ")}`;

    // 전체 개수
    const totalResult = await queryOne<{ count: string }>(
      `SELECT COUNT(*) as count FROM component_standards ${whereClause}`,
      values
    );
    const total = parseInt(totalResult?.count || "0");

    // 카테고리별 집계
    const byCategory = await query<{ category: string; count: string }>(
      `SELECT category, COUNT(*) as count 
       FROM component_standards 
       ${whereClause}
       GROUP BY category`,
      values
    );

    // 상태별 집계
    const byStatus = await query<{ is_active: string; count: string }>(
      `SELECT is_active, COUNT(*) as count 
       FROM component_standards 
       GROUP BY is_active`
    );

    return {
      total,
      byCategory: byCategory.map((item) => ({
        category: item.category,
        count: parseInt(item.count),
      })),
      byStatus: byStatus.map((item) => ({
        status: item.is_active,
        count: parseInt(item.count),
      })),
    };
  }

  /**
   * 컴포넌트 코드 중복 체크
   */
  async checkDuplicate(
    component_code: string,
    company_code?: string
  ): Promise<boolean> {
    const whereConditions: string[] = ["component_code = $1"];
    const values: any[] = [component_code];

    // 회사 코드가 있고 "*"가 아닌 경우에만 조건 추가
    if (company_code && company_code !== "*") {
      whereConditions.push("company_code = $2");
      values.push(company_code);
    }

    const whereClause = `WHERE ${whereConditions.join(" AND ")}`;

    const existingComponent = await queryOne<any>(
      `SELECT * FROM component_standards ${whereClause} LIMIT 1`,
      values
    );

    return !!existingComponent;
  }
}

export default new ComponentStandardService();
