import type { CommonCode } from '@/lib/domain/common-code';

/**
 * 가맹몰 상세 등록·수정 입력 규칙 — 순수 검증만 담는다.
 *
 * 기획 BO-MAL-002 ①의 필수 항목은 업체명·카테고리·업체 연락처·우편번호·노출 상태·바우처 사용·
 * 대표이미지다. 업체 항목(업체명·연락처·우편번호·주소)은 이 화면에서 직접 입력한다(사용자 확정) —
 * 가맹점이 없으면 새로 만들고, 있으면 함께 고친다.
 */

export const DESCRIPTION_MAX_LENGTH = 200;
export const CLOSED_DAYS_MAX_LENGTH = 100;
export const SORT_ORDER_MAX = 9999;
export const MERCHANT_NAME_MAX_LENGTH = 100;
export const ADDRESS_MAX_LENGTH = 200;
const TIME_PATTERN = /^([01]\d|2[0-3]):[0-5]\d$/;
const POSTAL_CODE_PATTERN = /^\d{5}$/;
const PHONE_PATTERN = /^[\d-]+$/;

/** 상세 화면이 함께 다루는 업체(가맹점) 항목 — 백엔드 `MngrVocBaseVo`의 일부. */
export type MerchantDetailMerchantValues = {
  name: string;
  phoneNumber: string;
  postalCode: string;
  address: string;
  addressDetail: string;
};

export type MerchantDetailValues = MerchantDetailMerchantValues & {
  /** 비어 있으면 가맹점을 새로 만든다. */
  frcsNo: string;
  categoryCode: string;
  description: string;
  openTime: string;
  closeTime: string;
  closedDays: string;
  isVisible: boolean;
  isVoucherUsable: boolean;
  /** 빈 값이면 null — 기획 ⑦ 미입력 시 등록일 내림차순. */
  sortOrder: number | null;
  thumbnailFileId: string;
  imageFileId: string;
};

export type MerchantDetailFormErrors = Partial<
  Record<
    | 'name'
    | 'phoneNumber'
    | 'postalCode'
    | 'address'
    | 'categoryCode'
    | 'description'
    | 'openTime'
    | 'closeTime'
    | 'closedDays'
    | 'sortOrder'
    | 'thumbnail'
    | 'images',
    string
  >
>;

export type MerchantDetailFormState =
  | { status: 'idle' }
  | { status: 'error'; message?: string; errors?: MerchantDetailFormErrors }
  /** `created`가 참이면 이번 저장으로 상세 행이 처음 생겼다 — 화면이 그 가맹점 주소로 옮겨 간다. */
  | { status: 'success'; frcsNo: string; created: boolean };

export const INITIAL_MERCHANT_DETAIL_FORM_STATE: MerchantDetailFormState = {
  status: 'idle',
};

type ValidationResult =
  | { ok: true; values: MerchantDetailValues }
  | { ok: false; errors: MerchantDetailFormErrors };

export function validateMerchantDetail(
  values: MerchantDetailValues,
  categories: readonly CommonCode[]
): ValidationResult {
  const errors: MerchantDetailFormErrors = {};

  const name = values.name.trim();
  if (!name) {
    errors.name = '업체명을 입력해 주세요.';
  } else if (name.length > MERCHANT_NAME_MAX_LENGTH) {
    errors.name = `업체명은 ${MERCHANT_NAME_MAX_LENGTH}자 이내로 입력해 주세요.`;
  }

  const phoneNumber = values.phoneNumber.trim();
  if (!phoneNumber) {
    errors.phoneNumber = '업체 연락처를 입력해 주세요.';
  } else if (!PHONE_PATTERN.test(phoneNumber)) {
    errors.phoneNumber = '연락처는 숫자와 -만 입력할 수 있습니다.';
  }

  const postalCode = values.postalCode.trim();
  if (!postalCode) {
    errors.postalCode = '우편번호를 입력해 주세요.';
  } else if (!POSTAL_CODE_PATTERN.test(postalCode)) {
    errors.postalCode = '우편번호는 숫자 5자리로 입력해 주세요.';
  }

  const address = values.address.trim();
  const addressDetail = values.addressDetail.trim();
  if (address.length > ADDRESS_MAX_LENGTH || addressDetail.length > ADDRESS_MAX_LENGTH) {
    errors.address = `주소는 ${ADDRESS_MAX_LENGTH}자 이내로 입력해 주세요.`;
  }

  if (!categories.some((code) => code.code === values.categoryCode)) {
    errors.categoryCode = '카테고리를 선택해 주세요.';
  }

  const description = values.description.trim();
  if (description.length > DESCRIPTION_MAX_LENGTH) {
    errors.description = `한줄 소개는 ${DESCRIPTION_MAX_LENGTH}자 이내로 입력해 주세요.`;
  }

  const openTime = values.openTime.trim();
  const closeTime = values.closeTime.trim();
  if (openTime && !TIME_PATTERN.test(openTime)) {
    errors.openTime = '영업 시작 시간 형식이 올바르지 않습니다.';
  }
  if (closeTime && !TIME_PATTERN.test(closeTime)) {
    errors.closeTime = '영업 종료 시간 형식이 올바르지 않습니다.';
  }

  const closedDays = values.closedDays.trim();
  if (closedDays.length > CLOSED_DAYS_MAX_LENGTH) {
    errors.closedDays = `휴무일은 ${CLOSED_DAYS_MAX_LENGTH}자 이내로 입력해 주세요.`;
  }

  if (
    values.sortOrder !== null &&
    (!Number.isInteger(values.sortOrder) ||
      values.sortOrder < 0 ||
      values.sortOrder > SORT_ORDER_MAX)
  ) {
    errors.sortOrder = `노출 순서는 0 이상 ${SORT_ORDER_MAX} 이하의 숫자로 입력해 주세요.`;
  }

  if (!values.thumbnailFileId) {
    errors.thumbnail = '대표이미지를 등록해 주세요.';
  }

  if (Object.keys(errors).length > 0) {
    return { ok: false, errors };
  }
  return {
    ok: true,
    values: {
      ...values,
      name,
      phoneNumber,
      postalCode,
      address,
      addressDetail,
      description,
      openTime,
      closeTime,
      closedDays,
    },
  };
}
