/**
 * 바코드 라벨 관리 서비스
 * ZD421 등 라벨 디자인 CRUD 및 기본 템플릿 제공
 */

import { v4 as uuidv4 } from "uuid";
import { query, queryOne, transaction } from "../database/db";
import { BarcodeLabelLayout } from "../types/barcode";

export interface BarcodeLabelMaster {
  label_id: string;
  label_name_kor: string;
  label_name_eng: string | null;
  description: string | null;
  width_mm: number;
  height_mm: number;
  layout_json: string | null;
  use_yn: string;
  created_at: string;
  created_by: string | null;
  updated_at: string | null;
  updated_by: string | null;
}

export interface BarcodeLabelTemplate {
  template_id: string;
  template_name_kor: string;
  template_name_eng: string | null;
  width_mm: number;
  height_mm: number;
  layout_json: string;
  sort_order: number;
}

export interface GetBarcodeLabelsParams {
  page?: number;
  limit?: number;
  searchText?: string;
  useYn?: string;
  sortBy?: string;
  sortOrder?: "ASC" | "DESC";
}

export interface GetBarcodeLabelsResult {
  items: BarcodeLabelMaster[];
  total: number;
  page: number;
  limit: number;
}

export class BarcodeLabelService {
  async getLabels(params: GetBarcodeLabelsParams): Promise<GetBarcodeLabelsResult> {
    const {
      page = 1,
      limit = 20,
      searchText = "",
      useYn = "Y",
      sortBy = "created_at",
      sortOrder = "DESC",
    } = params;

    const offset = (page - 1) * limit;
    const conditions: string[] = [];
    const values: any[] = [];
    let idx = 1;

    if (useYn) {
      conditions.push(`use_yn = $${idx++}`);
      values.push(useYn);
    }
    if (searchText) {
      conditions.push(`(label_name_kor LIKE $${idx} OR label_name_eng LIKE $${idx})`);
      values.push(`%${searchText}%`);
      idx++;
    }
    const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";

    const countSql = `SELECT COUNT(*) as total FROM barcode_labels ${where}`;
    const countRow = await queryOne<{ total: string }>(countSql, values);
    const total = parseInt(countRow?.total || "0", 10);

    const listSql = `
      SELECT label_id, label_name_kor, label_name_eng, description, width_mm, height_mm,
             layout_json, use_yn, created_at, created_by, updated_at, updated_by
      FROM barcode_labels ${where}
      ORDER BY ${sortBy} ${sortOrder}
      LIMIT $${idx++} OFFSET $${idx}
    `;
    const items = await query<BarcodeLabelMaster>(listSql, [...values, limit, offset]);

    return { items, total, page, limit };
  }

  async getLabelById(labelId: string): Promise<BarcodeLabelMaster | null> {
    const sql = `
      SELECT label_id, label_name_kor, label_name_eng, description, width_mm, height_mm,
             layout_json, use_yn, created_at, created_by, updated_at, updated_by
      FROM barcode_labels WHERE label_id = $1
    `;
    return queryOne<BarcodeLabelMaster>(sql, [labelId]);
  }

  async getLayout(labelId: string): Promise<BarcodeLabelLayout | null> {
    const row = await this.getLabelById(labelId);
    if (!row?.layout_json) return null;
    try {
      return JSON.parse(row.layout_json) as BarcodeLabelLayout;
    } catch {
      return null;
    }
  }

  async createLabel(
    data: { labelNameKor: string; labelNameEng?: string; description?: string; templateId?: string },
    userId: string
  ): Promise<string> {
    const labelId = `LBL_${uuidv4().replace(/-/g, "").substring(0, 20)}`;
    let widthMm = 50;
    let heightMm = 30;
    let layoutJson: string | null = null;

    if (data.templateId) {
      const t = await this.getTemplateById(data.templateId);
      if (t) {
        widthMm = t.width_mm;
        heightMm = t.height_mm;
        layoutJson = t.layout_json;
      }
    }
    if (!layoutJson) {
      const defaultLayout: BarcodeLabelLayout = {
        width_mm: widthMm,
        height_mm: heightMm,
        components: [],
      };
      layoutJson = JSON.stringify(defaultLayout);
    }

    await query(
      `INSERT INTO barcode_labels (label_id, label_name_kor, label_name_eng, description, width_mm, height_mm, layout_json, use_yn, created_by)
       VALUES ($1, $2, $3, $4, $5, $6, $7, 'Y', $8)`,
      [
        labelId,
        data.labelNameKor,
        data.labelNameEng || null,
        data.description || null,
        widthMm,
        heightMm,
        layoutJson,
        userId,
      ]
    );
    return labelId;
  }

  async updateLabel(
    labelId: string,
    data: { labelNameKor?: string; labelNameEng?: string; description?: string; useYn?: string },
    userId: string
  ): Promise<boolean> {
    const setClauses: string[] = [];
    const values: any[] = [];
    let idx = 1;
    if (data.labelNameKor !== undefined) {
      setClauses.push(`label_name_kor = $${idx++}`);
      values.push(data.labelNameKor);
    }
    if (data.labelNameEng !== undefined) {
      setClauses.push(`label_name_eng = $${idx++}`);
      values.push(data.labelNameEng);
    }
    if (data.description !== undefined) {
      setClauses.push(`description = $${idx++}`);
      values.push(data.description);
    }
    if (data.useYn !== undefined) {
      setClauses.push(`use_yn = $${idx++}`);
      values.push(data.useYn);
    }
    if (setClauses.length === 0) return false;
    setClauses.push(`updated_at = CURRENT_TIMESTAMP`);
    setClauses.push(`updated_by = $${idx++}`);
    values.push(userId);
    values.push(labelId);

    const updated = await query<{ label_id: string }>(
      `UPDATE barcode_labels SET ${setClauses.join(", ")} WHERE label_id = $${idx} RETURNING label_id`,
      values
    );
    return updated.length > 0;
  }

  async saveLayout(labelId: string, layout: BarcodeLabelLayout, userId: string): Promise<boolean> {
    const layoutJson = JSON.stringify(layout);
    await query(
      `UPDATE barcode_labels SET width_mm = $1, height_mm = $2, layout_json = $3, updated_at = CURRENT_TIMESTAMP, updated_by = $4 WHERE label_id = $5`,
      [layout.width_mm, layout.height_mm, layoutJson, userId, labelId]
    );
    return true;
  }

  async deleteLabel(labelId: string): Promise<boolean> {
    const deleted = await query<{ label_id: string }>(
      `DELETE FROM barcode_labels WHERE label_id = $1 RETURNING label_id`,
      [labelId]
    );
    return deleted.length > 0;
  }

  async copyLabel(labelId: string, userId: string): Promise<string | null> {
    const row = await this.getLabelById(labelId);
    if (!row) return null;
    const newId = `LBL_${uuidv4().replace(/-/g, "").substring(0, 20)}`;
    await query(
      `INSERT INTO barcode_labels (label_id, label_name_kor, label_name_eng, description, width_mm, height_mm, layout_json, use_yn, created_by)
       VALUES ($1, $2 || ' (복사)', $3, $4, $5, $6, $7, 'Y', $8)`,
      [
        newId,
        row.label_name_kor,
        row.label_name_eng,
        row.description,
        row.width_mm,
        row.height_mm,
        row.layout_json,
        userId,
      ]
    );
    return newId;
  }

  async getTemplates(): Promise<BarcodeLabelTemplate[]> {
    const sql = `
      SELECT template_id, template_name_kor, template_name_eng, width_mm, height_mm, layout_json, sort_order
      FROM barcode_label_templates ORDER BY sort_order, template_id
    `;
    const rows = await query<BarcodeLabelTemplate>(sql);
    return rows || [];
  }

  async getTemplateById(templateId: string): Promise<BarcodeLabelTemplate | null> {
    const sql = `SELECT template_id, template_name_kor, template_name_eng, width_mm, height_mm, layout_json, sort_order
                 FROM barcode_label_templates WHERE template_id = $1`;
    return queryOne<BarcodeLabelTemplate>(sql, [templateId]);
  }
}

export default new BarcodeLabelService();
