package com.zioinfo.kintex.tenant;

import com.zioinfo.kintex.common.error.ApiException;
import com.zioinfo.kintex.common.error.ErrorCode;
import com.zioinfo.kintex.tenant.dto.TenantAdminDto;
import com.zioinfo.kintex.tenant.dto.TenantCreateRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 플랫폼 슈퍼관리자 테넌트 관리·온보딩 서비스 (M18 · §1A-4).
 * 1단계는 테넌트 마스터 목록 조회 + 등록(온보딩 위저드 1단계)만 제공한다. 격리 스코핑 전 스윕은 2단계.
 */
@Service
public class TenantAdminService {

    /** 코드 규칙: 소문자·숫자·하이픈, 2~40자(서브도메인·tenant_id 안전). */
    private static final Pattern CODE = Pattern.compile("^[a-z0-9-]{2,40}$");

    private final TenantMapper mapper;
    private final TenantResolver resolver;

    public TenantAdminService(TenantMapper mapper, TenantResolver resolver) {
        this.mapper = mapper;
        this.resolver = resolver;
    }

    /** 전 테넌트 목록(행사·사용자 수 포함). */
    public List<TenantAdminDto> list() {
        List<Map<String, Object>> rows = mapper.findAdminList();
        List<TenantAdminDto> out = new ArrayList<>(rows == null ? 0 : rows.size());
        if (rows != null) {
            for (Map<String, Object> r : rows) {
                out.add(new TenantAdminDto(
                        str(r.get("code")), str(r.get("name")), str(r.get("domain")),
                        str(r.get("status")), lng(r.get("events")), lng(r.get("users")),
                        str(r.get("createdAt"))));
            }
        }
        return out;
    }

    /** 테넌트 등록(온보딩 1단계). 코드 정규화·검증·중복 차단 후 마스터 생성, 해소 캐시 무효화. */
    @Transactional
    public TenantAdminDto create(TenantCreateRequest req) {
        if (req == null || req.code() == null || req.code().isBlank()) {
            throw new ApiException(ErrorCode.VALIDATION, "테넌트 코드는 필수입니다.");
        }
        String code = req.code().trim().toLowerCase(Locale.ROOT);
        if (!CODE.matcher(code).matches()) {
            throw new ApiException(ErrorCode.VALIDATION, "테넌트 코드는 소문자·숫자·하이픈 2~40자여야 합니다.");
        }
        if (req.name() == null || req.name().isBlank()) {
            throw new ApiException(ErrorCode.VALIDATION, "표시명은 필수입니다.");
        }
        if (mapper.existsById(code) > 0) {
            throw new ApiException(ErrorCode.CONFLICT, "이미 존재하는 테넌트 코드입니다.");
        }
        String domain = req.domain() == null ? null : req.domain().trim().toLowerCase(Locale.ROOT);
        String status = (req.status() == null || req.status().isBlank()) ? "onboarding" : req.status().trim();
        mapper.insert(code, req.name().trim(), domain, status);
        resolver.invalidate();
        return new TenantAdminDto(code, req.name().trim(), domain, status, 0L, 0L, null);
    }

    private static String str(Object o) {
        return o == null ? null : String.valueOf(o);
    }

    private static long lng(Object o) {
        if (o instanceof Number n) {
            return n.longValue();
        }
        try {
            return o == null ? 0L : Long.parseLong(String.valueOf(o));
        } catch (NumberFormatException e) {
            return 0L;
        }
    }
}
