/**
 * 세금계산서 서비스
 * 세금계산서 CRUD 및 비즈니스 로직 처리
 */

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

// 비용 유형 타입
export type CostType = "purchase" | "installation" | "repair" | "maintenance" | "disposal" | "other";

// 세금계산서 타입 정의
export interface TaxInvoice {
  id: string;
  company_code: string;
  invoice_number: string;
  invoice_type: "sales" | "purchase"; // 매출/매입
  invoice_status: "draft" | "issued" | "sent" | "cancelled";

  // 공급자 정보
  supplier_business_no: string;
  supplier_name: string;
  supplier_ceo_name: string;
  supplier_address: string;
  supplier_business_type: string;
  supplier_business_item: string;

  // 공급받는자 정보
  buyer_business_no: string;
  buyer_name: string;
  buyer_ceo_name: string;
  buyer_address: string;
  buyer_email: string;

  // 금액 정보
  supply_amount: number;
  tax_amount: number;
  total_amount: number;

  // 날짜 정보
  invoice_date: string;
  issue_date: string | null;

  // 기타
  remarks: string;
  order_id: string | null;
  customer_id: string | null;

  // 첨부파일 (JSON 배열로 저장)
  attachments: TaxInvoiceAttachment[] | null;

  // 비용 유형 (구매/설치/수리/유지보수/폐기/기타)
  cost_type: CostType | null;

  created_date: string;
  updated_date: string;
  writer: string;
}

// 첨부파일 타입
export interface TaxInvoiceAttachment {
  id: string;
  file_name: string;
  file_path: string;
  file_size: number;
  file_type: string;
  uploaded_at: string;
  uploaded_by: string;
}

export interface TaxInvoiceItem {
  id: string;
  tax_invoice_id: string;
  company_code: string;
  item_seq: number;
  item_date: string;
  item_name: string;
  item_spec: string;
  quantity: number;
  unit_price: number;
  supply_amount: number;
  tax_amount: number;
  remarks: string;
}

export interface CreateTaxInvoiceDto {
  invoice_type: "sales" | "purchase";
  supplier_business_no?: string;
  supplier_name?: string;
  supplier_ceo_name?: string;
  supplier_address?: string;
  supplier_business_type?: string;
  supplier_business_item?: string;
  buyer_business_no?: string;
  buyer_name?: string;
  buyer_ceo_name?: string;
  buyer_address?: string;
  buyer_email?: string;
  supply_amount: number;
  tax_amount: number;
  total_amount: number;
  invoice_date: string;
  remarks?: string;
  order_id?: string;
  customer_id?: string;
  items?: CreateTaxInvoiceItemDto[];
  attachments?: TaxInvoiceAttachment[]; // 첨부파일
  cost_type?: CostType; // 비용 유형
}

export interface CreateTaxInvoiceItemDto {
  item_date?: string;
  item_name: string;
  item_spec?: string;
  quantity: number;
  unit_price: number;
  supply_amount: number;
  tax_amount: number;
  remarks?: string;
}

export interface TaxInvoiceListParams {
  page?: number;
  pageSize?: number;
  invoice_type?: "sales" | "purchase";
  invoice_status?: string;
  start_date?: string;
  end_date?: string;
  search?: string;
  buyer_name?: string;
  cost_type?: CostType; // 비용 유형 필터
}

export class TaxInvoiceService {
  /**
   * 세금계산서 번호 채번
   * 형식: YYYYMM-NNNNN (예: 202512-00001)
   */
  static async generateInvoiceNumber(companyCode: string): Promise<string> {
    const now = new Date();
    const yearMonth = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}`;
    const prefix = `${yearMonth}-`;

    // 해당 월의 마지막 번호 조회
    const result = await query<{ max_num: string }>(
      `SELECT invoice_number as max_num 
       FROM tax_invoice 
       WHERE company_code = $1 
         AND invoice_number LIKE $2
       ORDER BY invoice_number DESC 
       LIMIT 1`,
      [companyCode, `${prefix}%`]
    );

    let nextNum = 1;
    if (result.length > 0 && result[0].max_num) {
      const lastNum = parseInt(result[0].max_num.split("-")[1], 10);
      nextNum = lastNum + 1;
    }

    return `${prefix}${String(nextNum).padStart(5, "0")}`;
  }

  /**
   * 세금계산서 목록 조회
   */
  static async getList(
    companyCode: string,
    params: TaxInvoiceListParams
  ): Promise<{ data: TaxInvoice[]; total: number; page: number; pageSize: number }> {
    const {
      page = 1,
      pageSize = 20,
      invoice_type,
      invoice_status,
      start_date,
      end_date,
      search,
      buyer_name,
      cost_type,
    } = params;

    const offset = (page - 1) * pageSize;
    const conditions: string[] = ["company_code = $1"];
    const values: any[] = [companyCode];
    let paramIndex = 2;

    if (invoice_type) {
      conditions.push(`invoice_type = $${paramIndex}`);
      values.push(invoice_type);
      paramIndex++;
    }

    if (invoice_status) {
      conditions.push(`invoice_status = $${paramIndex}`);
      values.push(invoice_status);
      paramIndex++;
    }

    if (start_date) {
      conditions.push(`invoice_date >= $${paramIndex}`);
      values.push(start_date);
      paramIndex++;
    }

    if (end_date) {
      conditions.push(`invoice_date <= $${paramIndex}`);
      values.push(end_date);
      paramIndex++;
    }

    if (search) {
      conditions.push(
        `(invoice_number ILIKE $${paramIndex} OR buyer_name ILIKE $${paramIndex} OR supplier_name ILIKE $${paramIndex})`
      );
      values.push(`%${search}%`);
      paramIndex++;
    }

    if (buyer_name) {
      conditions.push(`buyer_name ILIKE $${paramIndex}`);
      values.push(`%${buyer_name}%`);
      paramIndex++;
    }

    if (cost_type) {
      conditions.push(`cost_type = $${paramIndex}`);
      values.push(cost_type);
      paramIndex++;
    }

    const whereClause = conditions.join(" AND ");

    // 전체 개수 조회
    const countResult = await query<{ count: string }>(
      `SELECT COUNT(*) as count FROM tax_invoice WHERE ${whereClause}`,
      values
    );
    const total = parseInt(countResult[0]?.count || "0", 10);

    // 데이터 조회
    values.push(pageSize, offset);
    const data = await query<TaxInvoice>(
      `SELECT * FROM tax_invoice 
       WHERE ${whereClause}
       ORDER BY created_date DESC
       LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`,
      values
    );

    return { data, total, page, pageSize };
  }

  /**
   * 세금계산서 상세 조회 (품목 포함)
   */
  static async getById(
    id: string,
    companyCode: string
  ): Promise<{ invoice: TaxInvoice; items: TaxInvoiceItem[] } | null> {
    const invoiceResult = await query<TaxInvoice>(
      `SELECT * FROM tax_invoice WHERE id = $1 AND company_code = $2`,
      [id, companyCode]
    );

    if (invoiceResult.length === 0) {
      return null;
    }

    const items = await query<TaxInvoiceItem>(
      `SELECT * FROM tax_invoice_item 
       WHERE tax_invoice_id = $1 AND company_code = $2
       ORDER BY item_seq`,
      [id, companyCode]
    );

    return { invoice: invoiceResult[0], items };
  }

  /**
   * 세금계산서 생성
   */
  static async create(
    data: CreateTaxInvoiceDto,
    companyCode: string,
    userId: string
  ): Promise<TaxInvoice> {
    return await transaction(async (client) => {
      // 세금계산서 번호 채번
      const invoiceNumber = await this.generateInvoiceNumber(companyCode);

      // 세금계산서 생성
      const invoiceResult = await client.query(
        `INSERT INTO tax_invoice (
          company_code, invoice_number, invoice_type, invoice_status,
          supplier_business_no, supplier_name, supplier_ceo_name, supplier_address,
          supplier_business_type, supplier_business_item,
          buyer_business_no, buyer_name, buyer_ceo_name, buyer_address, buyer_email,
          supply_amount, tax_amount, total_amount, invoice_date,
          remarks, order_id, customer_id, attachments, cost_type, writer
        ) VALUES (
          $1, $2, $3, 'draft',
          $4, $5, $6, $7, $8, $9,
          $10, $11, $12, $13, $14,
          $15, $16, $17, $18,
          $19, $20, $21, $22, $23, $24
        ) RETURNING *`,
        [
          companyCode,
          invoiceNumber,
          data.invoice_type,
          data.supplier_business_no || null,
          data.supplier_name || null,
          data.supplier_ceo_name || null,
          data.supplier_address || null,
          data.supplier_business_type || null,
          data.supplier_business_item || null,
          data.buyer_business_no || null,
          data.buyer_name || null,
          data.buyer_ceo_name || null,
          data.buyer_address || null,
          data.buyer_email || null,
          data.supply_amount,
          data.tax_amount,
          data.total_amount,
          data.invoice_date,
          data.remarks || null,
          data.order_id || null,
          data.customer_id || null,
          data.attachments ? JSON.stringify(data.attachments) : null,
          data.cost_type || null,
          userId,
        ]
      );

      const invoice = invoiceResult.rows[0];

      // 품목 생성
      if (data.items && data.items.length > 0) {
        for (let i = 0; i < data.items.length; i++) {
          const item = data.items[i];
          await client.query(
            `INSERT INTO tax_invoice_item (
              tax_invoice_id, company_code, item_seq,
              item_date, item_name, item_spec, quantity, unit_price,
              supply_amount, tax_amount, remarks
            ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
            [
              invoice.id,
              companyCode,
              i + 1,
              item.item_date || null,
              item.item_name,
              item.item_spec || null,
              item.quantity,
              item.unit_price,
              item.supply_amount,
              item.tax_amount,
              item.remarks || null,
            ]
          );
        }
      }

      logger.info("세금계산서 생성 완료", {
        invoiceId: invoice.id,
        invoiceNumber,
        companyCode,
        userId,
      });

      return invoice;
    });
  }

  /**
   * 세금계산서 수정
   */
  static async update(
    id: string,
    data: Partial<CreateTaxInvoiceDto>,
    companyCode: string,
    userId: string
  ): Promise<TaxInvoice | null> {
    return await transaction(async (client) => {
      // 기존 세금계산서 확인
      const existing = await client.query(
        `SELECT * FROM tax_invoice WHERE id = $1 AND company_code = $2`,
        [id, companyCode]
      );

      if (existing.rows.length === 0) {
        return null;
      }

      // 발행된 세금계산서는 수정 불가
      if (existing.rows[0].invoice_status !== "draft") {
        throw new Error("발행된 세금계산서는 수정할 수 없습니다.");
      }

      // 세금계산서 수정
      const updateResult = await client.query(
        `UPDATE tax_invoice SET
          supplier_business_no = COALESCE($3, supplier_business_no),
          supplier_name = COALESCE($4, supplier_name),
          supplier_ceo_name = COALESCE($5, supplier_ceo_name),
          supplier_address = COALESCE($6, supplier_address),
          supplier_business_type = COALESCE($7, supplier_business_type),
          supplier_business_item = COALESCE($8, supplier_business_item),
          buyer_business_no = COALESCE($9, buyer_business_no),
          buyer_name = COALESCE($10, buyer_name),
          buyer_ceo_name = COALESCE($11, buyer_ceo_name),
          buyer_address = COALESCE($12, buyer_address),
          buyer_email = COALESCE($13, buyer_email),
          supply_amount = COALESCE($14, supply_amount),
          tax_amount = COALESCE($15, tax_amount),
          total_amount = COALESCE($16, total_amount),
          invoice_date = COALESCE($17, invoice_date),
          remarks = COALESCE($18, remarks),
          attachments = $19,
          cost_type = COALESCE($20, cost_type),
          updated_date = NOW()
        WHERE id = $1 AND company_code = $2
        RETURNING *`,
        [
          id,
          companyCode,
          data.supplier_business_no,
          data.supplier_name,
          data.supplier_ceo_name,
          data.supplier_address,
          data.supplier_business_type,
          data.supplier_business_item,
          data.buyer_business_no,
          data.buyer_name,
          data.buyer_ceo_name,
          data.buyer_address,
          data.buyer_email,
          data.supply_amount,
          data.tax_amount,
          data.total_amount,
          data.invoice_date,
          data.remarks,
          data.attachments ? JSON.stringify(data.attachments) : null,
          data.cost_type,
        ]
      );

      // 품목 업데이트 (기존 삭제 후 재생성)
      if (data.items) {
        await client.query(
          `DELETE FROM tax_invoice_item WHERE tax_invoice_id = $1 AND company_code = $2`,
          [id, companyCode]
        );

        for (let i = 0; i < data.items.length; i++) {
          const item = data.items[i];
          await client.query(
            `INSERT INTO tax_invoice_item (
              tax_invoice_id, company_code, item_seq,
              item_date, item_name, item_spec, quantity, unit_price,
              supply_amount, tax_amount, remarks
            ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
            [
              id,
              companyCode,
              i + 1,
              item.item_date || null,
              item.item_name,
              item.item_spec || null,
              item.quantity,
              item.unit_price,
              item.supply_amount,
              item.tax_amount,
              item.remarks || null,
            ]
          );
        }
      }

      logger.info("세금계산서 수정 완료", { invoiceId: id, companyCode, userId });

      return updateResult.rows[0];
    });
  }

  /**
   * 세금계산서 삭제
   */
  static async delete(id: string, companyCode: string, userId: string): Promise<boolean> {
    return await transaction(async (client) => {
      // 기존 세금계산서 확인
      const existing = await client.query(
        `SELECT * FROM tax_invoice WHERE id = $1 AND company_code = $2`,
        [id, companyCode]
      );

      if (existing.rows.length === 0) {
        return false;
      }

      // 발행된 세금계산서는 삭제 불가
      if (existing.rows[0].invoice_status !== "draft") {
        throw new Error("발행된 세금계산서는 삭제할 수 없습니다.");
      }

      // 품목 삭제
      await client.query(
        `DELETE FROM tax_invoice_item WHERE tax_invoice_id = $1 AND company_code = $2`,
        [id, companyCode]
      );

      // 세금계산서 삭제
      await client.query(`DELETE FROM tax_invoice WHERE id = $1 AND company_code = $2`, [
        id,
        companyCode,
      ]);

      logger.info("세금계산서 삭제 완료", { invoiceId: id, companyCode, userId });

      return true;
    });
  }

  /**
   * 세금계산서 발행 (상태 변경)
   */
  static async issue(id: string, companyCode: string, userId: string): Promise<TaxInvoice | null> {
    const result = await query<TaxInvoice>(
      `UPDATE tax_invoice SET
        invoice_status = 'issued',
        issue_date = NOW(),
        updated_date = NOW()
      WHERE id = $1 AND company_code = $2 AND invoice_status = 'draft'
      RETURNING *`,
      [id, companyCode]
    );

    if (result.length === 0) {
      return null;
    }

    logger.info("세금계산서 발행 완료", { invoiceId: id, companyCode, userId });

    return result[0];
  }

  /**
   * 세금계산서 취소
   */
  static async cancel(
    id: string,
    companyCode: string,
    userId: string,
    reason?: string
  ): Promise<TaxInvoice | null> {
    const result = await query<TaxInvoice>(
      `UPDATE tax_invoice SET
        invoice_status = 'cancelled',
        remarks = CASE WHEN $3 IS NOT NULL THEN remarks || ' [취소사유: ' || $3 || ']' ELSE remarks END,
        updated_date = NOW()
      WHERE id = $1 AND company_code = $2 AND invoice_status IN ('draft', 'issued')
      RETURNING *`,
      [id, companyCode, reason || null]
    );

    if (result.length === 0) {
      return null;
    }

    logger.info("세금계산서 취소 완료", { invoiceId: id, companyCode, userId, reason });

    return result[0];
  }

  /**
   * 월별 통계 조회
   */
  static async getMonthlyStats(
    companyCode: string,
    year: number,
    month: number
  ): Promise<{
    sales: { count: number; supply_amount: number; tax_amount: number; total_amount: number };
    purchase: { count: number; supply_amount: number; tax_amount: number; total_amount: number };
  }> {
    const startDate = `${year}-${String(month).padStart(2, "0")}-01`;
    const endDate = new Date(year, month, 0).toISOString().split("T")[0]; // 해당 월 마지막 날

    const result = await query<{
      invoice_type: string;
      count: string;
      supply_amount: string;
      tax_amount: string;
      total_amount: string;
    }>(
      `SELECT 
        invoice_type,
        COUNT(*) as count,
        COALESCE(SUM(supply_amount), 0) as supply_amount,
        COALESCE(SUM(tax_amount), 0) as tax_amount,
        COALESCE(SUM(total_amount), 0) as total_amount
      FROM tax_invoice
      WHERE company_code = $1 
        AND invoice_date >= $2 
        AND invoice_date <= $3
        AND invoice_status != 'cancelled'
      GROUP BY invoice_type`,
      [companyCode, startDate, endDate]
    );

    const stats = {
      sales: { count: 0, supply_amount: 0, tax_amount: 0, total_amount: 0 },
      purchase: { count: 0, supply_amount: 0, tax_amount: 0, total_amount: 0 },
    };

    for (const row of result) {
      const type = row.invoice_type as "sales" | "purchase";
      stats[type] = {
        count: parseInt(row.count, 10),
        supply_amount: parseFloat(row.supply_amount),
        tax_amount: parseFloat(row.tax_amount),
        total_amount: parseFloat(row.total_amount),
      };
    }

    return stats;
  }

  /**
   * 비용 유형별 통계 조회
   */
  static async getCostTypeStats(
    companyCode: string,
    year?: number,
    month?: number
  ): Promise<{
    by_cost_type: Array<{
      cost_type: CostType | null;
      count: number;
      supply_amount: number;
      tax_amount: number;
      total_amount: number;
    }>;
    by_month: Array<{
      year_month: string;
      cost_type: CostType | null;
      count: number;
      total_amount: number;
    }>;
    summary: {
      total_count: number;
      total_amount: number;
      purchase_amount: number;
      installation_amount: number;
      repair_amount: number;
      maintenance_amount: number;
      disposal_amount: number;
      other_amount: number;
    };
  }> {
    const conditions: string[] = ["company_code = $1", "invoice_status != 'cancelled'"];
    const values: any[] = [companyCode];
    let paramIndex = 2;

    // 연도/월 필터
    if (year && month) {
      const startDate = `${year}-${String(month).padStart(2, "0")}-01`;
      const endDate = new Date(year, month, 0).toISOString().split("T")[0];
      conditions.push(`invoice_date >= $${paramIndex} AND invoice_date <= $${paramIndex + 1}`);
      values.push(startDate, endDate);
      paramIndex += 2;
    } else if (year) {
      conditions.push(`EXTRACT(YEAR FROM invoice_date) = $${paramIndex}`);
      values.push(year);
      paramIndex++;
    }

    const whereClause = conditions.join(" AND ");

    // 비용 유형별 집계
    const byCostType = await query<{
      cost_type: CostType | null;
      count: string;
      supply_amount: string;
      tax_amount: string;
      total_amount: string;
    }>(
      `SELECT 
        cost_type,
        COUNT(*) as count,
        COALESCE(SUM(supply_amount), 0) as supply_amount,
        COALESCE(SUM(tax_amount), 0) as tax_amount,
        COALESCE(SUM(total_amount), 0) as total_amount
      FROM tax_invoice
      WHERE ${whereClause}
      GROUP BY cost_type
      ORDER BY total_amount DESC`,
      values
    );

    // 월별 비용 유형 집계
    const byMonth = await query<{
      year_month: string;
      cost_type: CostType | null;
      count: string;
      total_amount: string;
    }>(
      `SELECT 
        TO_CHAR(invoice_date, 'YYYY-MM') as year_month,
        cost_type,
        COUNT(*) as count,
        COALESCE(SUM(total_amount), 0) as total_amount
      FROM tax_invoice
      WHERE ${whereClause}
      GROUP BY TO_CHAR(invoice_date, 'YYYY-MM'), cost_type
      ORDER BY year_month DESC, cost_type`,
      values
    );

    // 전체 요약
    const summaryResult = await query<{
      total_count: string;
      total_amount: string;
      purchase_amount: string;
      installation_amount: string;
      repair_amount: string;
      maintenance_amount: string;
      disposal_amount: string;
      other_amount: string;
    }>(
      `SELECT 
        COUNT(*) as total_count,
        COALESCE(SUM(total_amount), 0) as total_amount,
        COALESCE(SUM(CASE WHEN cost_type = 'purchase' THEN total_amount ELSE 0 END), 0) as purchase_amount,
        COALESCE(SUM(CASE WHEN cost_type = 'installation' THEN total_amount ELSE 0 END), 0) as installation_amount,
        COALESCE(SUM(CASE WHEN cost_type = 'repair' THEN total_amount ELSE 0 END), 0) as repair_amount,
        COALESCE(SUM(CASE WHEN cost_type = 'maintenance' THEN total_amount ELSE 0 END), 0) as maintenance_amount,
        COALESCE(SUM(CASE WHEN cost_type = 'disposal' THEN total_amount ELSE 0 END), 0) as disposal_amount,
        COALESCE(SUM(CASE WHEN cost_type = 'other' THEN total_amount ELSE 0 END), 0) as other_amount
      FROM tax_invoice
      WHERE ${whereClause}`,
      values
    );

    const summary = summaryResult[0] || {
      total_count: "0",
      total_amount: "0",
      purchase_amount: "0",
      installation_amount: "0",
      repair_amount: "0",
      maintenance_amount: "0",
      disposal_amount: "0",
      other_amount: "0",
    };

    return {
      by_cost_type: byCostType.map((row) => ({
        cost_type: row.cost_type,
        count: parseInt(row.count, 10),
        supply_amount: parseFloat(row.supply_amount),
        tax_amount: parseFloat(row.tax_amount),
        total_amount: parseFloat(row.total_amount),
      })),
      by_month: byMonth.map((row) => ({
        year_month: row.year_month,
        cost_type: row.cost_type,
        count: parseInt(row.count, 10),
        total_amount: parseFloat(row.total_amount),
      })),
      summary: {
        total_count: parseInt(summary.total_count, 10),
        total_amount: parseFloat(summary.total_amount),
        purchase_amount: parseFloat(summary.purchase_amount),
        installation_amount: parseFloat(summary.installation_amount),
        repair_amount: parseFloat(summary.repair_amount),
        maintenance_amount: parseFloat(summary.maintenance_amount),
        disposal_amount: parseFloat(summary.disposal_amount),
        other_amount: parseFloat(summary.other_amount),
      },
    };
  }
}

