package net.siegeln.cameleer.saas.vendor;

import net.siegeln.cameleer.saas.identity.LogtoManagementClient;
import net.siegeln.cameleer.saas.provisioning.ProvisioningProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class EmailConnectorService {

    private static final Logger log = LoggerFactory.getLogger(EmailConnectorService.class);
    private static final String SMTP_FACTORY_ID = "simple-mail-transfer-protocol";

    private final LogtoManagementClient logtoClient;
    private final ProvisioningProperties provisioningProps;

    public EmailConnectorService(LogtoManagementClient logtoClient, ProvisioningProperties provisioningProps) {
        this.logtoClient = logtoClient;
        this.provisioningProps = provisioningProps;
    }

    public record SmtpConfig(String host, int port, String username, String password, String fromEmail) {}

    public record EmailConnectorStatus(
        String connectorId,
        String factoryId,
        String host,
        int port,
        String username,
        String fromEmail,
        boolean registrationEnabled
    ) {}

    /** Get the current email connector config, or null if none is configured. */
    @SuppressWarnings("unchecked")
    public EmailConnectorStatus getEmailConnector() {
        var connectors = logtoClient.listConnectors();
        var emailConnector = connectors.stream()
            .filter(c -> "Email".equals(c.get("type")))
            .findFirst()
            .orElse(null);

        if (emailConnector == null) {
            return null;
        }

        var config = (Map<String, Object>) emailConnector.getOrDefault("config", Map.of());
        var auth = (Map<String, Object>) config.getOrDefault("auth", Map.of());
        String host = String.valueOf(config.getOrDefault("host", ""));
        int port = config.containsKey("port") ? ((Number) config.get("port")).intValue() : 587;
        String username = String.valueOf(auth.getOrDefault("user", ""));
        String fromEmail = String.valueOf(config.getOrDefault("fromEmail", ""));

        boolean registrationEnabled = isRegistrationEnabled();

        return new EmailConnectorStatus(
            String.valueOf(emailConnector.get("id")),
            String.valueOf(emailConnector.get("connectorId")),
            host, port, username, fromEmail, registrationEnabled
        );
    }

    /** Create or update the SMTP email connector. Returns the connector status. */
    public EmailConnectorStatus saveSmtpConnector(SmtpConfig smtp, Boolean registrationEnabled) {
        var connectorConfig = buildSmtpConfig(smtp);

        // Check if an email connector already exists
        var existing = getEmailConnector();
        if (existing != null) {
            logtoClient.updateConnector(existing.connectorId(), connectorConfig);
            log.info("Updated SMTP email connector: {}", existing.connectorId());
        } else {
            var result = logtoClient.createConnector(SMTP_FACTORY_ID, connectorConfig);
            log.info("Created SMTP email connector: {}", result != null ? result.get("id") : "unknown");
        }

        // Handle registration toggle
        boolean enableReg = registrationEnabled != null ? registrationEnabled : (existing == null);
        setRegistrationEnabled(enableReg);

        return getEmailConnector();
    }

    /** Delete the email connector and disable registration. */
    public void deleteEmailConnector() {
        var existing = getEmailConnector();
        if (existing != null) {
            logtoClient.deleteConnector(existing.connectorId());
            setRegistrationEnabled(false);
            log.info("Deleted email connector: {}", existing.connectorId());
        }
    }

    /** Send a test email through the configured connector. */
    public void sendTestEmail(String toEmail) {
        var existing = getEmailConnector();
        if (existing == null) {
            throw new IllegalStateException("No email connector configured");
        }
        // Re-read the full config from Logto to pass to the test endpoint
        var connectors = logtoClient.listConnectors();
        @SuppressWarnings("unchecked")
        var emailConnector = connectors.stream()
            .filter(c -> "Email".equals(c.get("type")))
            .findFirst()
            .orElseThrow(() -> new IllegalStateException("Email connector not found"));
        @SuppressWarnings("unchecked")
        var config = (Map<String, Object>) emailConnector.getOrDefault("config", Map.of());
        logtoClient.testConnector(existing.factoryId(), toEmail, config);
    }

    /** Set registration mode on the Logto sign-in experience. */
    public void setRegistrationEnabled(boolean enabled) {
        if (enabled) {
            logtoClient.updateSignInExperience(Map.of(
                "signInMode", "SignInAndRegister",
                "signUp", Map.of(
                    "identifiers", List.of("email"),
                    "password", true,
                    "verify", true
                ),
                "signIn", Map.of(
                    "methods", List.of(
                        Map.of("identifier", "email", "password", true, "verificationCode", false, "isPasswordPrimary", true),
                        Map.of("identifier", "username", "password", true, "verificationCode", false, "isPasswordPrimary", true)
                    )
                )
            ));
        } else {
            logtoClient.updateSignInExperience(Map.of(
                "signInMode", "SignIn",
                "signUp", Map.of(
                    "identifiers", List.of("username"),
                    "password", true,
                    "verify", false
                ),
                "signIn", Map.of(
                    "methods", List.of(
                        Map.of("identifier", "email", "password", true, "verificationCode", false, "isPasswordPrimary", true),
                        Map.of("identifier", "username", "password", true, "verificationCode", false, "isPasswordPrimary", true)
                    )
                )
            ));
        }
    }

    /** Check if registration is currently enabled in Logto. */
    @SuppressWarnings("unchecked")
    private boolean isRegistrationEnabled() {
        var signInExp = logtoClient.getSignInExperience();
        if (signInExp == null) return false;
        return "SignInAndRegister".equals(signInExp.get("signInMode"));
    }

    /** Load an email template from classpath and resolve the watermark URL placeholder. */
    private String loadTemplate(String filename) {
        try {
            String content = new ClassPathResource("email-templates/" + filename)
                .getContentAsString(StandardCharsets.UTF_8);
            String watermarkUrl = provisioningProps.publicProtocol() + "://"
                + provisioningProps.publicHost() + "/platform/assets/email-watermark.png";
            return content.replace("{{watermarkUrl}}", watermarkUrl);
        } catch (IOException e) {
            throw new IllegalStateException("Failed to load email template: " + filename, e);
        }
    }

    /** Build the Logto SMTP connector config with Cameleer-branded email templates. */
    private Map<String, Object> buildSmtpConfig(SmtpConfig smtp) {
        var config = new HashMap<String, Object>();
        config.put("host", smtp.host());
        config.put("port", smtp.port());
        config.put("auth", Map.of("user", smtp.username(), "pass", smtp.password()));
        config.put("fromEmail", smtp.fromEmail());
        config.put("templates", List.of(
            Map.of(
                "usageType", "Register",
                "contentType", "text/html",
                "subject", "Your caravan pass is almost ready",
                "content", loadTemplate("register.html")
            ),
            Map.of(
                "usageType", "SignIn",
                "contentType", "text/html",
                "subject", "Your Cameleer sign-in code",
                "content", loadTemplate("sign-in.html")
            ),
            Map.of(
                "usageType", "ForgotPassword",
                "contentType", "text/html",
                "subject", "Reset your Cameleer password",
                "content", loadTemplate("forgot-password.html")
            ),
            Map.of(
                "usageType", "Generic",
                "contentType", "text/html",
                "subject", "Your Cameleer verification code",
                "content", loadTemplate("generic.html")
            )
        ));
        return config;
    }
}
