package com.zioinfo.kintex.security;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * 최초 관리자 프로비저닝 — <b>비밀번호는 env 주입만</b>(ADMIN_PASSWORD). 하드코딩·admin123 시드 절대 금지(계약 §5B-3).
 * <p>kintex.security.admin-seed.enabled=true 이고 email/password 가 모두 주입될 때만 멱등 upsert 한다.
 * 값이 없으면 아무 것도 하지 않는다(기본 관리자 계정 없음). 비밀번호는 BCrypt 해시로만 저장하며 로그에 남기지 않는다.
 */
@Component
public class AdminAccountSeeder implements ApplicationRunner {

    private static final Logger log = LoggerFactory.getLogger(AdminAccountSeeder.class);

    private final SecurityPolicyProperties props;
    private final JdbcTemplate jdbc;
    private final PasswordEncoder passwordEncoder;

    public AdminAccountSeeder(SecurityPolicyProperties props, JdbcTemplate jdbc,
                              PasswordEncoder passwordEncoder) {
        this.props = props;
        this.jdbc = jdbc;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public void run(ApplicationArguments args) {
        SecurityPolicyProperties.AdminSeed seed = props.getAdminSeed();
        if (!seed.isEnabled()) {
            return;
        }
        if (isBlank(seed.getEmail()) || isBlank(seed.getPassword())) {
            log.warn("admin-seed enabled 이나 ADMIN_EMAIL/ADMIN_PASSWORD 미주입 → 관리자 시드 건너뜀");
            return;
        }
        String hash = passwordEncoder.encode(seed.getPassword());
        // 멱등 upsert: 신규면 생성, 기존이면 해시·역할·활성만 갱신(비번은 항상 env 값 기준).
        jdbc.update("""
                INSERT INTO app_user (id, email, display_name, password_hash, hall_manager,
                                      role_code, status, verify_method)
                VALUES (?, ?, ?, ?, true, 'ADMIN', 'ACTIVE', 'EMAIL')
                ON CONFLICT (email) DO UPDATE SET
                    password_hash = EXCLUDED.password_hash,
                    role_code     = 'ADMIN',
                    hall_manager  = true,
                    status        = 'ACTIVE',
                    updated_at    = now()
                """,
                "admin-" + Integer.toHexString(seed.getEmail().toLowerCase().hashCode()),
                seed.getEmail().toLowerCase(), seed.getDisplayName(), hash);
        log.info("관리자 계정 프로비저닝 완료(email 마스킹): {}", mask(seed.getEmail()));
    }

    private static boolean isBlank(String s) {
        return s == null || s.isBlank();
    }

    private static String mask(String email) {
        int at = email.indexOf('@');
        if (at <= 1) {
            return "***";
        }
        return email.charAt(0) + "***" + email.substring(at);
    }
}
