package net.siegeln.cameleer.saas.config;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.siegeln.cameleer.saas.tenant.TenantEntity;
import net.siegeln.cameleer.saas.tenant.TenantRepository;
import net.siegeln.cameleer.saas.tenant.TenantStatus;
import net.siegeln.cameleer.saas.tenant.Tier;
import net.siegeln.cameleer.saas.license.LicenseEntity;
import net.siegeln.cameleer.saas.license.LicenseRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.io.File;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Map;

@Component
public class BootstrapDataSeeder implements ApplicationRunner {

    private static final Logger log = LoggerFactory.getLogger(BootstrapDataSeeder.class);
    private static final String BOOTSTRAP_FILE = "/data/bootstrap/logto-bootstrap.json";

    private final TenantRepository tenantRepository;
    private final LicenseRepository licenseRepository;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public BootstrapDataSeeder(TenantRepository tenantRepository,
                                LicenseRepository licenseRepository) {
        this.tenantRepository = tenantRepository;
        this.licenseRepository = licenseRepository;
    }

    @Override
    public void run(ApplicationArguments args) {
        File file = new File(BOOTSTRAP_FILE);
        if (!file.exists()) {
            log.info("No bootstrap file found at {} — skipping data seeding", BOOTSTRAP_FILE);
            return;
        }

        try {
            JsonNode config = objectMapper.readTree(file);
            String orgId = getField(config, "organizationId");
            String tenantName = getField(config, "tenantName");
            String tenantSlug = getField(config, "tenantSlug");

            if (orgId == null || tenantSlug == null) {
                log.info("Bootstrap file missing organizationId or tenantSlug — skipping");
                return;
            }

            // Check if tenant already exists
            if (tenantRepository.existsBySlug(tenantSlug)) {
                log.info("Tenant '{}' already exists — skipping bootstrap seeding", tenantSlug);
                return;
            }

            log.info("Seeding bootstrap tenant '{}'...", tenantSlug);

            // Create tenant
            TenantEntity tenant = new TenantEntity();
            tenant.setName(tenantName != null ? tenantName : "Example Tenant");
            tenant.setSlug(tenantSlug);
            tenant.setTier(Tier.LOW);
            tenant.setStatus(TenantStatus.ACTIVE);
            tenant.setLogtoOrgId(orgId);
            tenant = tenantRepository.save(tenant);
            log.info("Created tenant: {} ({})", tenant.getSlug(), tenant.getId());

            // Create license
            LicenseEntity license = new LicenseEntity();
            license.setTenantId(tenant.getId());
            license.setTier("LOW");
            license.setFeatures(Map.of(
                    "topology", true,
                    "lineage", false,
                    "correlation", false,
                    "debugger", false,
                    "replay", false
            ));
            license.setLimits(Map.of(
                    "max_agents", 3,
                    "retention_days", 7,
                    "max_environments", 1
            ));
            license.setIssuedAt(Instant.now());
            license.setExpiresAt(Instant.now().plus(365, ChronoUnit.DAYS));
            license.setToken("bootstrap-license");
            licenseRepository.save(license);
            log.info("Created license for tenant '{}'", tenantSlug);

            log.info("Bootstrap data seeding complete.");
        } catch (Exception e) {
            log.error("Failed to seed bootstrap data: {}", e.getMessage(), e);
        }
    }

    private String getField(JsonNode node, String field) {
        return node.has(field) ? node.get(field).asText() : null;
    }
}
