package kr.iotdoor.boot.service;

import kr.iotdoor.boot.config.IotdoorProperties;
import kr.iotdoor.boot.mapper.UserMapper;
import kr.iotdoor.boot.model.user.UserAccount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.time.LocalDateTime;
import java.util.UUID;

@Configuration
public class AdminAccountInitializer {

    private static final Logger LOGGER = LoggerFactory.getLogger(AdminAccountInitializer.class);

    @Bean
    public ApplicationRunner adminUserSeedRunner(
        UserMapper userMapper,
        JdbcTemplate jdbcTemplate,
        IotdoorProperties properties,
        PasswordEncoder passwordEncoder
    ) {
        return args -> {
            String adminUsername = properties.getSecurity().getAdminUsername();
            if (userMapper.countByUserId(adminUsername) > 0) {
                UserAccount existing = userMapper.selectByUserId(adminUsername);
                if (existing != null && !isBcryptHash(existing.getPswd())) {
                    jdbcTemplate.update("""
                        UPDATE TN_USER
                        SET
                            PSWD = ?,
                            USER_NM = ?,
                            USER_STTS_CD = ?,
                            USER_TYPE_CD = ?,
                            LOCK_YN = ?,
                            LGN_FAIL_NMTM = 0,
                            LOCK_DT = NULL
                        WHERE USER_ID = ?
                        """,
                        passwordEncoder.encode(properties.getSecurity().getAdminPassword()),
                        properties.getSecurity().getAdminDisplayName(),
                        "A",
                        "ADM",
                        "N",
                        adminUsername
                    );
                    LOGGER.info("Normalized legacy admin account for Spring Security login. username={}", adminUsername);
                }
                return;
            }

            UserAccount userAccount = new UserAccount();
            userAccount.setUserIdntfNo(UUID.randomUUID().toString().replace("-", ""));
            userAccount.setUserId(adminUsername);
            userAccount.setPswd(passwordEncoder.encode(properties.getSecurity().getAdminPassword()));
            userAccount.setUserNm(properties.getSecurity().getAdminDisplayName());
            userAccount.setEmlAddr("admin@iotdoor.local");
            userAccount.setUserSttsCd("A");
            userAccount.setUserTypeCd("ADM");
            userAccount.setJoinDt(LocalDateTime.now());
            userAccount.setIndvdlInfoAgreDt(LocalDateTime.now());
            userAccount.setLockYn("N");
            userAccount.setLgnFailNmtm(0);

            if (hasLegacyColumns(jdbcTemplate)) {
                jdbcTemplate.update("""
                    INSERT INTO TN_USER (
                        USER_IDNTF_NO,
                        GROUP_IDNTF_NO,
                        AUTHRT_CD,
                        USER_ID,
                        PSWD,
                        USER_NM,
                        EML_ADDR,
                        USER_STTS_CD,
                        USER_TYPE_CD,
                        JOIN_DT,
                        INDVDL_INFO_AGRE_DT,
                        LOCK_YN,
                        LGN_FAIL_NMTM,
                        LOCK_DT,
                        LAST_LGN_DT
                    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                    """,
                    userAccount.getUserIdntfNo(),
                    "group-boot-default",
                    "ROLE_ADMIN",
                    userAccount.getUserId(),
                    userAccount.getPswd(),
                    userAccount.getUserNm(),
                    userAccount.getEmlAddr(),
                    userAccount.getUserSttsCd(),
                    userAccount.getUserTypeCd(),
                    userAccount.getJoinDt(),
                    userAccount.getIndvdlInfoAgreDt(),
                    userAccount.getLockYn(),
                    userAccount.getLgnFailNmtm(),
                    userAccount.getLockDt(),
                    userAccount.getLastLgnDt()
                );
            } else {
                userMapper.insertUser(userAccount);
            }

            LOGGER.info("Seeded default admin account into TN_USER. username={}", adminUsername);
        };
    }

    private boolean hasLegacyColumns(JdbcTemplate jdbcTemplate) {
        Integer count = jdbcTemplate.queryForObject("""
            SELECT COUNT(*)
            FROM information_schema.COLUMNS
            WHERE TABLE_SCHEMA = DATABASE()
              AND TABLE_NAME = 'TN_USER'
              AND COLUMN_NAME IN ('GROUP_IDNTF_NO', 'AUTHRT_CD')
            """, Integer.class);
        return count != null && count == 2;
    }

    private boolean isBcryptHash(String value) {
        if (value == null) {
            return false;
        }
        return value.startsWith("$2a$") || value.startsWith("$2b$") || value.startsWith("$2y$");
    }
}
