/**
 * 입력 타입 처리 서비스
 * VARCHAR 통일 방식에서 입력 타입별 형변환 및 검증 처리
 */

import { InputType } from "../types/input-types";
import { logger } from "../utils/logger";

export interface ValidationResult {
  isValid: boolean;
  message?: string;
  convertedValue?: string;
}

export class InputTypeService {
  /**
   * 데이터 저장 전 형변환 (화면 입력값 → DB 저장값)
   * 모든 값을 VARCHAR(500)에 저장하기 위해 문자열로 변환
   */
  static convertForStorage(value: any, inputType: InputType): string {
    if (value === null || value === undefined) {
      return "";
    }

    try {
      switch (inputType) {
        case "text":
        case "select":
        case "radio":
          return String(value).trim();

        case "number":
          if (value === "" || value === null || value === undefined) {
            return "0";
          }
          const num = parseFloat(String(value));
          return isNaN(num) ? "0" : String(num);

        case "date":
          if (!value || value === "") {
            return "";
          }
          const date = new Date(value);
          if (isNaN(date.getTime())) {
            logger.warn(`Invalid date value: ${value}`);
            return "";
          }
          return date.toISOString().split("T")[0]; // YYYY-MM-DD 형식

        case "checkbox":
          // 다양한 형태의 true 값을 "Y"로, 나머지는 "N"으로 변환
          const truthyValues = ["true", "1", "Y", "yes", "on", true, 1];
          return truthyValues.includes(value) ? "Y" : "N";

        case "code":
        case "entity":
          return String(value || "").trim();

        default:
          return String(value);
      }
    } catch (error) {
      logger.error(`Error converting value for storage: ${error}`, {
        value,
        inputType,
      });
      return String(value || "");
    }
  }

  /**
   * 화면 표시용 형변환 (DB 저장값 → 화면 표시값)
   * VARCHAR에서 읽어온 문자열을 적절한 타입으로 변환
   */
  static convertForDisplay(value: string, inputType: InputType): any {
    if (!value && value !== "0") {
      // 빈 값 처리
      switch (inputType) {
        case "number":
          return 0;
        case "checkbox":
          return false;
        default:
          return "";
      }
    }

    try {
      switch (inputType) {
        case "text":
        case "select":
        case "radio":
        case "code":
        case "entity":
          return value;

        case "number":
          const num = parseFloat(value);
          return isNaN(num) ? 0 : num;

        case "date":
          // YYYY-MM-DD 형식 그대로 반환 (HTML date input 호환)
          return value;

        case "checkbox":
          return value === "Y" || value === "true" || value === "1";

        default:
          return value;
      }
    } catch (error) {
      logger.error(`Error converting value for display: ${error}`, {
        value,
        inputType,
      });
      return value;
    }
  }

  /**
   * 입력값 검증
   * 저장 전에 값이 해당 입력 타입에 적합한지 검증
   */
  static validate(value: any, inputType: InputType): ValidationResult {
    // 빈 값은 일반적으로 허용 (필수 여부는 별도 검증)
    if (!value && value !== 0 && value !== false) {
      return {
        isValid: true,
        convertedValue: this.convertForStorage(value, inputType),
      };
    }

    try {
      switch (inputType) {
        case "text":
        case "select":
        case "radio":
        case "code":
        case "entity":
          const strValue = String(value).trim();
          if (strValue.length > 500) {
            return {
              isValid: false,
              message: "입력값이 너무 깁니다. (최대 500자)",
            };
          }
          return {
            isValid: true,
            convertedValue: this.convertForStorage(value, inputType),
          };

        case "number":
          const num = parseFloat(String(value));
          if (isNaN(num)) {
            return {
              isValid: false,
              message: "숫자 형식이 올바르지 않습니다.",
            };
          }
          return {
            isValid: true,
            convertedValue: this.convertForStorage(value, inputType),
          };

        case "date":
          if (!value) {
            return { isValid: true, convertedValue: "" };
          }
          const date = new Date(value);
          if (isNaN(date.getTime())) {
            return {
              isValid: false,
              message: "날짜 형식이 올바르지 않습니다.",
            };
          }
          return {
            isValid: true,
            convertedValue: this.convertForStorage(value, inputType),
          };

        case "checkbox":
          // 체크박스는 모든 값을 허용 (Y/N으로 변환)
          return {
            isValid: true,
            convertedValue: this.convertForStorage(value, inputType),
          };

        default:
          return {
            isValid: true,
            convertedValue: this.convertForStorage(value, inputType),
          };
      }
    } catch (error) {
      logger.error(`Error validating value: ${error}`, { value, inputType });
      return {
        isValid: false,
        message: "값 검증 중 오류가 발생했습니다.",
      };
    }
  }

  /**
   * 배치 데이터 변환 (여러 필드를 한번에 처리)
   */
  static convertBatchForStorage(
    data: Record<string, any>,
    columnTypes: Record<string, InputType>
  ): Record<string, string> {
    const converted: Record<string, string> = {};

    for (const [columnName, value] of Object.entries(data)) {
      const inputType = columnTypes[columnName];
      if (inputType) {
        converted[columnName] = this.convertForStorage(value, inputType);
      } else {
        // 입력 타입이 정의되지 않은 경우 기본적으로 text로 처리
        converted[columnName] = this.convertForStorage(value, "text");
      }
    }

    return converted;
  }

  /**
   * 배치 데이터 표시용 변환
   */
  static convertBatchForDisplay(
    data: Record<string, string>,
    columnTypes: Record<string, InputType>
  ): Record<string, any> {
    const converted: Record<string, any> = {};

    for (const [columnName, value] of Object.entries(data)) {
      const inputType = columnTypes[columnName];
      if (inputType) {
        converted[columnName] = this.convertForDisplay(value, inputType);
      } else {
        // 입력 타입이 정의되지 않은 경우 문자열 그대로 반환
        converted[columnName] = value;
      }
    }

    return converted;
  }

  /**
   * 배치 데이터 검증
   */
  static validateBatch(
    data: Record<string, any>,
    columnTypes: Record<string, InputType>
  ): {
    isValid: boolean;
    errors: Record<string, string>;
    convertedData: Record<string, string>;
  } {
    const errors: Record<string, string> = {};
    const convertedData: Record<string, string> = {};

    for (const [columnName, value] of Object.entries(data)) {
      const inputType = columnTypes[columnName];
      if (inputType) {
        const result = this.validate(value, inputType);
        if (!result.isValid) {
          errors[columnName] = result.message || "검증 실패";
        } else {
          convertedData[columnName] = result.convertedValue || "";
        }
      } else {
        // 입력 타입이 정의되지 않은 경우 기본적으로 text로 처리
        convertedData[columnName] = this.convertForStorage(value, "text");
      }
    }

    return {
      isValid: Object.keys(errors).length === 0,
      errors,
      convertedData,
    };
  }
}
