package com.erp.provisioning;

import com.erp.tenant.TenantDbSettings;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.security.SecureRandom;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 테넌트 DB 의 COMPANY_ADMIN 계정 관련 조회/재설정.
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class CompanyAdminService {

    private final TenantDbSettings settings;
    private final PasswordEncoder passwordEncoder;

    /**
     * 해당 회사 tenant DB 의 COMPANY_ADMIN 계정 1건 조회.
     * 비밀번호 해시는 반환하지 않음. 평문 비번도 없음.
     */
    public Map<String, Object> getAdmin(String dbName) {
        Map<String, Object> out = new LinkedHashMap<>();
        try (Connection c = DriverManager.getConnection(
                settings.buildJdbcUrl(dbName), settings.username(), settings.password());
             PreparedStatement ps = c.prepareStatement(
                     "SELECT user_id, user_name, status, force_password_change, created_date " +
                             "FROM user_info WHERE user_type='COMPANY_ADMIN' " +
                             "ORDER BY created_date ASC LIMIT 1")) {
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    out.put("user_id", rs.getString("user_id"));
                    out.put("user_name", rs.getString("user_name"));
                    out.put("status", rs.getString("status"));
                    out.put("force_password_change", rs.getBoolean("force_password_change"));
                    out.put("created_date", rs.getTimestamp("created_date"));
                    out.put("found", true);
                } else {
                    out.put("found", false);
                }
            }
        } catch (SQLException e) {
            log.error("[CompanyAdmin] getAdmin failed db={} err={}", dbName, e.getMessage());
            out.put("found", false);
            out.put("error", e.getMessage());
        }
        return out;
    }

    /**
     * 관리자 비번 재설정. 새 랜덤 비번 생성 → BCrypt 저장 → force_password_change=true.
     * 평문 비번은 1회만 반환 (호출자가 UI 에 1회 노출 후 파기).
     *
     * @return { admin_user_id, new_password } 또는 { error }
     */
    public Map<String, Object> resetAdminPassword(String dbName) {
        String newPlain = generateRandomPassword();
        String hash = passwordEncoder.encode(newPlain);
        Map<String, Object> out = new LinkedHashMap<>();

        try (Connection c = DriverManager.getConnection(
                settings.buildJdbcUrl(dbName), settings.username(), settings.password())) {

            // 대상 user_id 먼저 조회
            String userId = null;
            try (PreparedStatement sel = c.prepareStatement(
                    "SELECT user_id FROM user_info WHERE user_type='COMPANY_ADMIN' ORDER BY created_date ASC LIMIT 1");
                 ResultSet rs = sel.executeQuery()) {
                if (rs.next()) userId = rs.getString(1);
            }
            if (userId == null) {
                out.put("error", "no_admin_found");
                return out;
            }

            try (PreparedStatement up = c.prepareStatement(
                    "UPDATE user_info SET user_password=?, force_password_change=TRUE " +
                            "WHERE user_id=? AND user_type='COMPANY_ADMIN'")) {
                up.setString(1, hash);
                up.setString(2, userId);
                int affected = up.executeUpdate();
                if (affected == 0) {
                    out.put("error", "no_rows_updated");
                    return out;
                }
                log.info("[CompanyAdmin] password reset: db={} user={}", dbName, userId);
            }

            out.put("admin_user_id", userId);
            out.put("new_password", newPlain);
            out.put("force_password_change", true);
            return out;
        } catch (SQLException e) {
            log.error("[CompanyAdmin] resetAdminPassword failed db={} err={}", dbName, e.getMessage());
            out.put("error", e.getMessage());
            return out;
        }
    }

    private static String generateRandomPassword() {
        String chars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789@#$";
        SecureRandom r = new SecureRandom();
        StringBuilder sb = new StringBuilder(14);
        for (int i = 0; i < 14; i++) sb.append(chars.charAt(r.nextInt(chars.length())));
        return sb.toString();
    }
}
