package service

import (
	"context"
	"fmt"
	"strings"

	"oci-portal/internal/oci"
)

// IdentityProviders 列出域内 SAML 身份提供者。
func (s *OciConfigService) IdentityProviders(ctx context.Context, id uint, domainID string) ([]oci.IdentityProviderInfo, error) {
	cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
	if err != nil {
		return nil, err
	}
	return s.client.ListIdentityProviders(ctx, cred, homeRegion, domainID)
}

// CreateIdentityProvider 创建禁用态 SAML IdP，激活另走 activate。
// 映射与 JIT 字段缺省时填控制台默认值（normalizeIdpInput）。
func (s *OciConfigService) CreateIdentityProvider(ctx context.Context, id uint, domainID string, in oci.CreateIdpInput) (oci.IdentityProviderInfo, error) {
	if strings.TrimSpace(in.Name) == "" {
		return oci.IdentityProviderInfo{}, fmt.Errorf("create identity provider: name is required")
	}
	if !strings.Contains(in.Metadata, "EntityDescriptor") {
		return oci.IdentityProviderInfo{}, fmt.Errorf("create identity provider: metadata must be a SAML metadata XML")
	}
	// IDCS 校验 iconUrl 必须是 http(s) URL，data URI 会被 400 拒绝
	if in.IconURL != "" && !strings.HasPrefix(in.IconURL, "http://") && !strings.HasPrefix(in.IconURL, "https://") {
		return oci.IdentityProviderInfo{}, fmt.Errorf("create identity provider: iconUrl 需为 http(s) 外链图片 URL")
	}
	cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
	if err != nil {
		return oci.IdentityProviderInfo{}, err
	}
	return s.client.CreateSamlIdentityProvider(ctx, cred, homeRegion, domainID, normalizeIdpInput(in))
}

// normalizeIdpInput 填充映射字段的控制台默认值：名称 ID 格式「无」、
// 目标域用户属性「用户名」（JIT 开关组合由 API 层的指针缺省决定）。
func normalizeIdpInput(in oci.CreateIdpInput) oci.CreateIdpInput {
	if in.NameIDFormat == "" {
		in.NameIDFormat = "saml-none"
	}
	if in.UserStoreAttribute == "" {
		in.UserStoreAttribute = "userName"
	}
	return in
}

// SetIdentityProviderEnabled 激活/停用 IdP 并同步登录页显示。
func (s *OciConfigService) SetIdentityProviderEnabled(ctx context.Context, id uint, domainID, idpID string, enabled bool) (oci.IdentityProviderInfo, error) {
	cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
	if err != nil {
		return oci.IdentityProviderInfo{}, err
	}
	return s.client.SetIdentityProviderEnabled(ctx, cred, homeRegion, domainID, idpID, enabled)
}

// DeleteIdentityProvider 级联删除 IdP：先删关联的免 MFA 规则，再从登录页
// 移除、停用、删除 IdP 本体。
func (s *OciConfigService) DeleteIdentityProvider(ctx context.Context, id uint, domainID, idpID string) error {
	cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
	if err != nil {
		return err
	}
	if err := s.deleteIdpExemptions(ctx, cred, homeRegion, domainID, idpID); err != nil {
		return err
	}
	return s.client.DeleteIdentityProvider(ctx, cred, homeRegion, domainID, idpID)
}

// deleteIdpExemptions 删除 sign-on 策略中引用目标 IdP 的免 MFA 规则。
func (s *OciConfigService) deleteIdpExemptions(ctx context.Context, cred oci.Credentials, region, domainID, idpID string) error {
	rules, err := s.client.ListConsoleSignOnRules(ctx, cred, region, domainID)
	if err != nil {
		return fmt.Errorf("list sign-on rules before delete idp: %w", err)
	}
	for _, r := range rules {
		if r.BuiltIn || !strings.Contains(r.ConditionValue, idpID) {
			continue
		}
		if err := s.client.DeleteMfaExemptionRule(ctx, cred, region, domainID, r.ID); err != nil {
			return fmt.Errorf("delete exemption rule %s: %w", r.Name, err)
		}
	}
	return nil
}

// DomainSamlMetadata 下载域的 SP SAML 元数据 XML（提供给 IdP 侧配置）。
func (s *OciConfigService) DomainSamlMetadata(ctx context.Context, id uint, domainID string) ([]byte, error) {
	cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
	if err != nil {
		return nil, err
	}
	return s.client.DownloadDomainSamlMetadata(ctx, cred, homeRegion, domainID)
}

// ConsoleSignOnRules 按优先级列出 OCI Console sign-on 策略的规则。
func (s *OciConfigService) ConsoleSignOnRules(ctx context.Context, id uint, domainID string) ([]oci.SignOnRuleInfo, error) {
	cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
	if err != nil {
		return nil, err
	}
	return s.client.ListConsoleSignOnRules(ctx, cred, homeRegion, domainID)
}

// CreateMfaExemption 为指定 IdP 创建免 MFA 规则并置为最高优先级。
func (s *OciConfigService) CreateMfaExemption(ctx context.Context, id uint, domainID, idpID string) (oci.SignOnRuleInfo, error) {
	if strings.TrimSpace(idpID) == "" {
		return oci.SignOnRuleInfo{}, fmt.Errorf("create mfa exemption: identityProviderId is required")
	}
	cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
	if err != nil {
		return oci.SignOnRuleInfo{}, err
	}
	name, err := s.exemptionRuleName(ctx, cred, homeRegion, domainID, idpID)
	if err != nil {
		return oci.SignOnRuleInfo{}, err
	}
	return s.client.CreateMfaExemptionRule(ctx, cred, homeRegion, domainID, idpID, name)
}

// exemptionRuleName 校验 IdP 存在并用其名称生成规则名。
func (s *OciConfigService) exemptionRuleName(ctx context.Context, cred oci.Credentials, region, domainID, idpID string) (string, error) {
	idps, err := s.client.ListIdentityProviders(ctx, cred, region, domainID)
	if err != nil {
		return "", err
	}
	for _, idp := range idps {
		if idp.ID == idpID {
			return "skip-mfa-" + idp.Name, nil
		}
	}
	return "", fmt.Errorf("create mfa exemption: identity provider %s not found", idpID)
}

// DeleteMfaExemption 删除免 MFA 规则并恢复其余规则优先级。
func (s *OciConfigService) DeleteMfaExemption(ctx context.Context, id uint, domainID, ruleID string) error {
	cred, homeRegion, err := s.credentialsAndHomeRegion(ctx, id)
	if err != nil {
		return err
	}
	return s.client.DeleteMfaExemptionRule(ctx, cred, homeRegion, domainID, ruleID)
}
