package dev.awesomedev.mirim.web.dto;

import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Past;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;

import java.time.LocalDate;

/**
 * 이 파일이 하는 일:
 * 회원가입 요청 본문(로그인 정보 + 인적사항)을 담는 DTO다.
 *
 * 학습 포인트: 검증 애노테이션(@NotBlank, @Size, @Pattern)을 필드에 붙여 두면,
 * 컨트롤러에서 @Valid를 만나는 순간 스프링이 자동으로 검사해 준다.
 * 검사에 실패하면 컨트롤러 코드가 실행되기도 전에 400 Bad Request가 반환된다.
 * "검증 규칙은 데이터 옆에 선언한다" — if문을 컨트롤러마다 반복해서 쓰지 않아도 되는 이유다.
 *
 * 학습 포인트 ②: 인적사항을 가입 때 한 번에 받는다. 개인정보는 꼭 필요한 최소한만 —
 * 주민번호·계좌번호는 여기 없다(민감정보는 종이 인사 절차로). StudentProfile 주석 참고.
 */
public record SignupRequest(

        /*
         * 아이디: 4자 이상, 영문/숫자만.
         * 학습 포인트: @Pattern의 정규식 ^[a-zA-Z0-9]+$ 은
         * "처음(^)부터 끝($)까지 영문 대소문자와 숫자만 1개 이상(+)"이라는 뜻이다.
         * 공백·한글·특수문자가 하나라도 섞이면 매칭에 실패한다.
         */
        @NotBlank(message = "아이디는 필수입니다.")
        @Size(min = 4, message = "아이디는 4자 이상이어야 합니다.")
        @Pattern(regexp = "^[a-zA-Z0-9]+$", message = "아이디는 영문과 숫자만 사용할 수 있습니다.")
        String username,

        // 비밀번호: 8자 이상. (원문은 서버에 저장되지 않고 BCrypt 해시만 저장된다)
        @NotBlank(message = "비밀번호는 필수입니다.")
        @Size(min = 8, message = "비밀번호는 8자 이상이어야 합니다.")
        String password,

        // 화면에 표시될 이름
        @NotBlank(message = "이름은 필수입니다.")
        String name,

        /*
         * 트랙: DEV(개발) 또는 DESIGN(디자인)만 허용.
         * 학습 포인트: 허용 값을 서버가 강제하지 않으면 프론트를 우회한 요청이
         * "HACKER" 같은 임의 값을 넣을 수 있다. 서버 검증이 항상 최종 방어선이다.
         */
        @NotBlank(message = "트랙은 필수입니다.")
        @Pattern(regexp = "^(DEV|DESIGN)$", message = "트랙은 DEV 또는 DESIGN만 선택할 수 있습니다.")
        String track,

        // ── 회사 이메일 (아이디 부분만. 도메인 @awesomedev.dev는 서버가 붙인다) ──
        // 학습 포인트: 정규식으로 이메일 아이디에 쓸 수 있는 글자만 허용한다.
        //   소문자·숫자·점·밑줄·하이픈. 대문자나 한글, @ 같은 건 못 넣는다(도메인은 우리가 붙이니까).
        @NotBlank(message = "회사 이메일 아이디는 필수입니다.")
        @Size(min = 2, max = 40, message = "이메일 아이디는 2~40자입니다.")
        @Pattern(regexp = "^[a-z0-9._-]+$", message = "이메일 아이디는 소문자·숫자·. _ - 만 쓸 수 있어요.")
        String companyEmailLocal,

        // ── 인적사항 ──
        @NotNull(message = "생년월일은 필수입니다.")
        @Past(message = "생년월일은 오늘보다 이전이어야 합니다.")
        LocalDate birthDate,       // 프론트에서 "2007-03-15" 형태 문자열 → Jackson이 LocalDate로 변환

        @NotBlank(message = "연락처는 필수입니다.")
        @Pattern(regexp = "^01[0-9]-?[0-9]{3,4}-?[0-9]{4}$", message = "휴대폰 번호 형식이 올바르지 않아요.")
        String phone,

        @NotBlank(message = "주소는 필수입니다.")
        String address,

        @NotBlank(message = "학교는 필수입니다.")
        String school,

        @NotBlank(message = "전공(학과)은 필수입니다.")
        String major,

        // ── 비상 연락처 ──
        @NotBlank(message = "비상 연락처 이름은 필수입니다.")
        String emergencyName,

        @NotBlank(message = "비상 연락처 관계는 필수입니다.")
        String emergencyRelation,   // 예: 부, 모, 형제

        @NotBlank(message = "비상 연락처 전화번호는 필수입니다.")
        @Pattern(regexp = "^01[0-9]-?[0-9]{3,4}-?[0-9]{4}$", message = "비상 연락처 전화번호 형식이 올바르지 않아요.")
        String emergencyPhone,

        /*
         * 개인정보 수집·이용 동의.
         * 학습 포인트: @AssertTrue는 "반드시 true여야 통과"다. 동의 없이 개인정보를
         * 수집하면 개인정보보호법 위반이므로, 화면 체크박스만 믿지 않고 서버가 다시 확인한다.
         * (Boolean이라 null도 올 수 있는데, @NotNull이 그 구멍을 막는다.)
         */
        @NotNull(message = "개인정보 수집·이용 동의가 필요합니다.")
        @AssertTrue(message = "개인정보 수집·이용에 동의해야 가입할 수 있습니다.")
        Boolean privacyConsent
) {
}
