package jp.co.example.kaiin.validation;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import jp.co.example.kaiin.model.KaiinMaster;

/**
 * 会員マスタ（KAIIN_MASTER）入力チェック。
 *
 * <p>チェック内容はすべて項目定義書（input/kaiin-item-teigi.csv）の
 * 「桁数」「必須」「形式」「備考」列から導出している。
 * <p>生成: Claude Code（項目定義書から自動生成・人手レビュー前）
 */
public class KaiinMasterValidator {

    /** 会員番号: K+7桁数字 */
    private static final Pattern KAIIN_NO_PTN = Pattern.compile("^K[0-9]{7}$");
    /** カナ: 全角カタカナ（長音・中点・全角スペースを許容） */
    private static final Pattern KANA_PTN = Pattern.compile("^[ァ-ヶー・０-９　]+$");
    /** メールアドレス（簡易形式チェック） */
    private static final Pattern MAIL_PTN = Pattern.compile("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");
    /** 電話番号: ハイフン区切り（例: 03-1234-5678 / 090-1234-5678） */
    private static final Pattern TEL_PTN = Pattern.compile("^0[0-9]{1,4}-[0-9]{1,4}-[0-9]{3,4}$");
    /** 生年月日の下限（項目定義書: 1900-01-01以降） */
    private static final LocalDate BIRTH_MIN = LocalDate.of(1900, 1, 1);

    /**
     * 入力チェックを実行し、エラーメッセージの一覧を返す。
     *
     * @param k    チェック対象
     * @param today 業務日付（生年月日の「過去日付」判定に使用）
     * @return エラーメッセージ一覧（エラーなしなら空リスト）
     */
    public List<String> validate(KaiinMaster k, LocalDate today) {
        List<String> errors = new ArrayList<>();

        // No.1 会員番号: 必須・K+7桁数字
        if (isEmpty(k.getKaiinNo())) {
            errors.add("会員番号は必須です。");
        } else if (!KAIIN_NO_PTN.matcher(k.getKaiinNo()).matches()) {
            errors.add("会員番号は「K+7桁数字」の形式で入力してください（例: K0000001）。");
        }

        // No.2 会員氏名: 必須・40文字以内
        if (isEmpty(k.getKaiinName())) {
            errors.add("会員氏名は必須です。");
        } else if (k.getKaiinName().length() > 40) {
            errors.add("会員氏名は40文字以内で入力してください。");
        }

        // No.3 会員氏名カナ: 必須・60文字以内・全角カタカナのみ
        if (isEmpty(k.getKaiinKana())) {
            errors.add("会員氏名カナは必須です。");
        } else {
            if (k.getKaiinKana().length() > 60) {
                errors.add("会員氏名カナは60文字以内で入力してください。");
            }
            if (!KANA_PTN.matcher(k.getKaiinKana()).matches()) {
                errors.add("会員氏名カナは全角カタカナで入力してください。");
            }
        }

        // No.4 メールアドレス: 必須・254文字以内・形式（一意性はDB制約で担保）
        if (isEmpty(k.getMailAddress())) {
            errors.add("メールアドレスは必須です。");
        } else {
            if (k.getMailAddress().length() > 254) {
                errors.add("メールアドレスは254文字以内で入力してください。");
            }
            if (!MAIL_PTN.matcher(k.getMailAddress()).matches()) {
                errors.add("メールアドレスの形式が不正です。");
            }
        }

        // No.5 電話番号: 任意・13文字以内・ハイフン区切り
        if (!isEmpty(k.getTelNo())) {
            if (k.getTelNo().length() > 13) {
                errors.add("電話番号は13文字以内で入力してください。");
            }
            if (!TEL_PTN.matcher(k.getTelNo()).matches()) {
                errors.add("電話番号はハイフン区切りで入力してください（例: 03-1234-5678）。");
            }
        }

        // No.6 性別区分: 任意・1/2/9
        if (!isEmpty(k.getSeibetsuKbn())
                && !"1".equals(k.getSeibetsuKbn())
                && !"2".equals(k.getSeibetsuKbn())
                && !"9".equals(k.getSeibetsuKbn())) {
            errors.add("性別区分は 1:男性 2:女性 9:回答しない のいずれかを指定してください。");
        }

        // No.7 生年月日: 任意・1900-01-01以降の過去日付
        if (k.getBirthDate() != null) {
            if (k.getBirthDate().isBefore(BIRTH_MIN)) {
                errors.add("生年月日は1900-01-01以降で入力してください。");
            }
            if (!k.getBirthDate().isBefore(today)) {
                errors.add("生年月日は過去の日付で入力してください。");
            }
        }

        // No.8 会員ランク区分: 必須・1/2/3
        if (isEmpty(k.getRankKbn())) {
            errors.add("会員ランク区分は必須です。");
        } else if (!"1".equals(k.getRankKbn()) && !"2".equals(k.getRankKbn()) && !"3".equals(k.getRankKbn())) {
            errors.add("会員ランク区分は 1:ゴールド 2:シルバー 3:ブロンズ のいずれかを指定してください。");
        }

        // No.9 ポイント残高: 必須（プリミティブのため0以上のみ）・9桁以内
        if (k.getPointZan() < 0) {
            errors.add("ポイント残高は0以上で入力してください。");
        } else if (k.getPointZan() > 999_999_999L) {
            errors.add("ポイント残高は9桁以内で入力してください。");
        }

        // No.10 退会フラグ: 必須・0/1
        if (isEmpty(k.getTaikaiFlg())) {
            errors.add("退会フラグは必須です。");
        } else if (!"0".equals(k.getTaikaiFlg()) && !"1".equals(k.getTaikaiFlg())) {
            errors.add("退会フラグは 0:在会 1:退会 のいずれかを指定してください。");
        }

        // No.11-12 登録日時・更新日時はシステム設定項目のため入力チェック対象外

        return errors;
    }

    private boolean isEmpty(String s) {
        return s == null || s.isEmpty();
    }
}
