package com.erp.provisioning;

import com.erp.tenant.CompanyResolver;
import com.erp.tenant.DbContextHolder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 회사 라이프사이클 액션 (비활성화 / 재활성화 / 영구 삭제).
 *
 * 비활성화: DB_STATUS='suspended' + DEACTIVATED_AT + DEACTIVATION_REASON 기록.
 *          로그인 필터가 suspended 를 403 처리 (기존 구현). DB 는 남겨둠.
 * 재활성화: DB_STATUS='active' + 위 2 필드 NULL 로 클리어.
 * 영구 삭제: DROP DATABASE + COMPANY_MNG row DELETE + CompanyResolver 캐시 무효화.
 *           절대 되돌릴 수 없음.
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class CompanyLifecycleService {

    private final SqlSession sqlSession;
    private final DatabaseCreator databaseCreator;
    private final CompanyResolver companyResolver;

    public Map<String, Object> getCompany(String companyCode) {
        String prevCtx = DbContextHolder.get();
        DbContextHolder.setMeta();
        try {
            Map<String, Object> p = new HashMap<>();
            p.put("company_code", companyCode);
            Map<String, Object> row = sqlSession.selectOne("provisioning.selectCompanyByCode", p);
            return row;
        } finally {
            restoreCtx(prevCtx);
        }
    }

    /**
     * 비활성화. 이미 suspended 면 no-op 리턴.
     * @return { status, subdomain } 성공 시 | { error } 실패 시
     */
    public Map<String, Object> deactivate(String companyCode, String reason) {
        String prevCtx = DbContextHolder.get();
        DbContextHolder.setMeta();
        try {
            Map<String, Object> company = getCompany(companyCode);
            if (company == null) return Map.of("error", "not_found");

            String curStatus = (String) company.get("db_status");
            if ("suspended".equals(curStatus)) {
                return Map.of("error", "already_suspended");
            }
            if ("provisioning".equals(curStatus)) {
                return Map.of("error", "cannot_suspend_while_provisioning");
            }

            Map<String, Object> p = new HashMap<>();
            p.put("company_code", companyCode);
            p.put("reason", reason);
            sqlSession.update("provisioning.deactivateCompany", p);
            companyResolver.invalidate((String) company.get("subdomain"));

            log.info("[CompanyLifecycle] deactivated company={} reason={}", companyCode, reason);
            Map<String, Object> out = new LinkedHashMap<>();
            out.put("status", "suspended");
            out.put("subdomain", company.get("subdomain"));
            return out;
        } finally {
            restoreCtx(prevCtx);
        }
    }

    public Map<String, Object> reactivate(String companyCode) {
        String prevCtx = DbContextHolder.get();
        DbContextHolder.setMeta();
        try {
            Map<String, Object> company = getCompany(companyCode);
            if (company == null) return Map.of("error", "not_found");

            String curStatus = (String) company.get("db_status");
            if (!"suspended".equals(curStatus)) {
                return Map.of("error", "not_suspended", "current_status", curStatus);
            }

            Map<String, Object> p = new HashMap<>();
            p.put("company_code", companyCode);
            sqlSession.update("provisioning.reactivateCompany", p);
            companyResolver.invalidate((String) company.get("subdomain"));

            log.info("[CompanyLifecycle] reactivated company={}", companyCode);
            Map<String, Object> out = new LinkedHashMap<>();
            out.put("status", "active");
            out.put("subdomain", company.get("subdomain"));
            return out;
        } finally {
            restoreCtx(prevCtx);
        }
    }

    /**
     * 영구 삭제. DROP DATABASE → COMPANY_MNG row DELETE.
     * DROP 이 실패해도 메타 row 는 남겨둠 (사용자가 수동 청소 후 재시도 하도록).
     */
    public Map<String, Object> delete(String companyCode) {
        String prevCtx = DbContextHolder.get();
        DbContextHolder.setMeta();
        try {
            Map<String, Object> company = getCompany(companyCode);
            if (company == null) return Map.of("error", "not_found");

            String dbName = (String) company.get("db_name");
            String subdomain = (String) company.get("subdomain");

            // 1. DROP DATABASE (실패해도 로그만, 예외 안 남) — dropDatabase 가 이미 그렇게 동작
            databaseCreator.dropDatabase(dbName);

            // 2. 메타 row 삭제
            Map<String, Object> p = new HashMap<>();
            p.put("company_code", companyCode);
            int affected = sqlSession.delete("provisioning.deleteCompany", p);

            companyResolver.invalidate(subdomain);

            log.warn("[CompanyLifecycle] ⚠ PERMANENTLY DELETED company={} db={} (rows_removed={})",
                    companyCode, dbName, affected);

            Map<String, Object> out = new LinkedHashMap<>();
            out.put("company_code", companyCode);
            out.put("db_name", dbName);
            out.put("subdomain", subdomain);
            out.put("meta_rows_removed", affected);
            return out;
        } finally {
            restoreCtx(prevCtx);
        }
    }

    private static void restoreCtx(String prev) {
        if (prev == null) DbContextHolder.clear();
        else DbContextHolder.set(prev);
    }
}
