package api

import (
	"errors"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"

	"oci-portal/internal/oci"
	"oci-portal/internal/service"
)

// ---- 流量与成本 ----

// @Summary  ---- 流量与成本 ----
// @Tags     计算
// @Param    id path int true "配置 ID"
// @Param    instanceId path string true "instanceId"
// @Success  200 {object} oci.InstanceTraffic
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/instances/{instanceId}/traffic [get]
func (h *ociConfigHandler) instanceTraffic(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	days, _ := strconv.Atoi(c.DefaultQuery("days", "30"))
	traffic, err := h.svc.InstanceTraffic(c.Request.Context(), id, c.Query("region"), c.Param("instanceId"), days)
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, traffic)
}

// @Summary  配置成本快照
// @Tags     成本
// @Param    id path int true "配置 ID"
// @Success  200 {array} oci.CostItem
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/costs [get]
func (h *ociConfigHandler) costs(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	q := oci.CostQuery{
		Granularity: c.Query("granularity"),
		QueryType:   c.Query("queryType"),
		GroupBy:     c.Query("groupBy"),
	}
	if t, err := time.Parse(time.RFC3339, c.Query("startTime")); err == nil {
		q.StartTime = t
	}
	if t, err := time.Parse(time.RFC3339, c.Query("endTime")); err == nil {
		q.EndTime = t
	}
	items, err := h.svc.Costs(c.Request.Context(), id, q)
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, items)
}

// ---- 租户审计日志 ----

// getAuditEvents 批式懒加载查询审计事件:cursor 为空自当前时刻首查,
// 非空从上次响应游标继续向更早回溯;limit 单批目标条数(缺省 100,上限 200);
// q 为服务端全文检索关键字,仅首查生效,续查沿用游标内嵌关键字。
//
// @Summary  批式懒加载查询租户 OCI 审计事件
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    cursor query string false "续查游标(上次响应原样带回)"
// @Param    limit query int false "单批目标条数,缺省 100,上限 200"
// @Param    q query string false "检索关键字(服务端全文匹配,支持 * 通配;仅首查生效)"
// @Success  200 {object} service.AuditEventsView
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/audit-events [get]
func (h *ociConfigHandler) getAuditEvents(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	limit, _ := strconv.Atoi(c.Query("limit"))
	q := service.AuditQuery{Region: c.Query("region"), Cursor: c.Query("cursor"), Limit: limit, Q: c.Query("q")}
	result, err := h.svc.AuditEvents(c.Request.Context(), id, q)
	if errors.Is(err, service.ErrInvalidAuditCursor) {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, result)
}

// getAuditEventDetail 按 eventId 取回原始事件 JSON:缓存命中秒开,
// 过期走事件时间小窗重查;仍不可得返回 404,前端降级展示精简字段。
//
// @Summary  按 eventId 取回原始事件 JSON:缓存命中秒开,
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Success  200 {object} rawDetailResponse "raw 为事件原文 JSON"
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/audit-events/detail [get]
func (h *ociConfigHandler) getAuditEventDetail(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	eventID := c.Query("eventId")
	eventTime, terr := time.Parse(time.RFC3339, c.Query("eventTime"))
	if eventID == "" || terr != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "eventId 与 eventTime(RFC3339)必填"})
		return
	}
	raw, err := h.svc.AuditEventDetail(c.Request.Context(), id, c.Query("region"), eventID, eventTime)
	if errors.Is(err, service.ErrAuditEventGone) {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, gin.H{"raw": raw})
}

// ---- 租户用户管理 ----

type createTenantUserRequest struct {
	Name        string `json:"name" binding:"required"`
	Description string `json:"description"`
	Email       string `json:"email"`
	GivenName   string `json:"givenName" binding:"required"`
	FamilyName  string `json:"familyName" binding:"required"`
	// 同时勾选时先授身份域管理员，再加入管理员组
	GrantDomainAdmin bool `json:"grantDomainAdmin"`
	AddToAdminGroup  bool `json:"addToAdminGroup"`
}

// @Summary  租户身份域列表
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Success  200 {array} oci.IdentityDomain
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/domains [get]
func (h *ociConfigHandler) listIdentityDomains(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	domains, err := h.svc.IdentityDomains(c.Request.Context(), id)
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, domains)
}

// @Summary  租户 IAM 用户列表
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Success  200 {array} oci.TenantUser
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/users [get]
func (h *ociConfigHandler) listTenantUsers(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	users, err := h.svc.TenantUsers(c.Request.Context(), id, c.Query("domainId"))
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, users)
}

// @Summary  租户用户详情
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param    userId path string true "userId"
// @Success  200 {object} oci.TenantUserDetail
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/users/{userId} [get]
func (h *ociConfigHandler) getTenantUserDetail(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	detail, err := h.svc.TenantUserDetail(c.Request.Context(), id, c.Query("domainId"), c.Param("userId"))
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, detail)
}

// @Summary  创建租户 IAM 用户
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param    body body createTenantUserRequest true "请求体"
// @Success  201 {object} oci.TenantUser
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/users [post]
func (h *ociConfigHandler) createTenantUser(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	var req createTenantUserRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	user, err := h.svc.CreateTenantUser(c.Request.Context(), id, c.Query("domainId"), oci.CreateTenantUserInput{
		Name:             req.Name,
		Description:      req.Description,
		Email:            req.Email,
		GivenName:        req.GivenName,
		FamilyName:       req.FamilyName,
		GrantDomainAdmin: req.GrantDomainAdmin,
		AddToAdminGroup:  req.AddToAdminGroup,
	})
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusCreated, user)
}

// updateTenantUserRequest 的字段全部可缺省：nil 不修改，传空串表示清空。
// 管理员字段为三态：true 授予/加入，false 撤销/移出，缺省不动。
type updateTenantUserRequest struct {
	Description      *string `json:"description"`
	Email            *string `json:"email"`
	GivenName        *string `json:"givenName"`
	FamilyName       *string `json:"familyName"`
	GrantDomainAdmin *bool   `json:"grantDomainAdmin"`
	AddToAdminGroup  *bool   `json:"addToAdminGroup"`
}

// @Summary  更新租户 IAM 用户
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param    userId path string true "userId"
// @Param    body body updateTenantUserRequest true "请求体"
// @Success  200 {object} oci.TenantUser
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/users/{userId} [put]
func (h *ociConfigHandler) updateTenantUser(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	var req updateTenantUserRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	user, err := h.svc.UpdateTenantUser(c.Request.Context(), id, c.Query("domainId"), c.Param("userId"), oci.UpdateTenantUserInput{
		Description:      req.Description,
		Email:            req.Email,
		GivenName:        req.GivenName,
		FamilyName:       req.FamilyName,
		GrantDomainAdmin: req.GrantDomainAdmin,
		AddToAdminGroup:  req.AddToAdminGroup,
	})
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, user)
}

// @Summary  删除租户 IAM 用户
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param    userId path string true "userId"
// @Success  204 "无内容"
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/users/{userId} [delete]
func (h *ociConfigHandler) deleteTenantUser(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	if err := h.svc.DeleteTenantUser(c.Request.Context(), id, c.Query("domainId"), c.Param("userId")); err != nil {
		respondError(c, err)
		return
	}
	c.Status(http.StatusNoContent)
}

// @Summary  重置租户用户密码
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param    userId path string true "userId"
// @Success  200 {object} passwordResponse "一次性明文密码"
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/users/{userId}/reset-password [post]
func (h *ociConfigHandler) resetTenantUserPassword(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	password, err := h.svc.ResetTenantUserPassword(c.Request.Context(), id, c.Query("domainId"), c.Param("userId"))
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, gin.H{"password": password})
}

// @Summary  清除用户 MFA 设备
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param    userId path string true "userId"
// @Success  200 {object} deletedTotpResponse
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/users/{userId}/mfa-devices [delete]
func (h *ociConfigHandler) deleteTenantUserMfa(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	deleted, err := h.svc.DeleteTenantUserMfa(c.Request.Context(), id, c.Query("domainId"), c.Param("userId"))
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, gin.H{"deletedTotpDevices": deleted})
}

// @Summary  清除用户全部 API Key
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    userId path string true "userId"
// @Success  200 {object} deletedApiKeysResponse
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/users/{userId}/api-keys [delete]
func (h *ociConfigHandler) deleteTenantUserApiKeys(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	includeCurrent := c.Query("includeCurrent") == "true"
	deleted, err := h.svc.DeleteTenantUserApiKeys(c.Request.Context(), id, c.Param("userId"), includeCurrent)
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, gin.H{"deletedApiKeys": deleted})
}

// ---- 域通知收件人与密码策略 ----

// @Summary  ---- 域通知收件人与密码策略 ----
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Success  200 {object} oci.NotificationRecipients
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/notification-recipients [get]
func (h *ociConfigHandler) getNotificationRecipients(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	recipients, err := h.svc.NotificationRecipients(c.Request.Context(), id, c.Query("domainId"))
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, recipients)
}

// @Summary  更新通知收件人
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param    body body object true "请求体(见接口说明)"
// @Success  200 {object} oci.NotificationRecipients
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/notification-recipients [put]
func (h *ociConfigHandler) updateNotificationRecipients(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	var req struct {
		Recipients []string `json:"recipients"` // 空列表表示关闭 test mode 恢复默认发送
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	recipients, err := h.svc.UpdateNotificationRecipients(c.Request.Context(), id, c.Query("domainId"), req.Recipients)
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, recipients)
}

// @Summary  密码策略列表
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Success  200 {array} oci.PasswordPolicyInfo
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/password-policies [get]
func (h *ociConfigHandler) listPasswordPolicies(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	policies, err := h.svc.PasswordPolicies(c.Request.Context(), id, c.Query("domainId"))
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, policies)
}

// @Summary  更新密码策略
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param    policyId path string true "policyId"
// @Param    body body object true "请求体(见接口说明)"
// @Success  200 {object} oci.PasswordPolicyInfo
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/password-policies/{policyId} [put]
func (h *ociConfigHandler) updatePasswordPolicy(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	var req struct {
		PasswordExpiresAfter  *int `json:"passwordExpiresAfter"`
		MinLength             *int `json:"minLength"`
		NumPasswordsInHistory *int `json:"numPasswordsInHistory"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	policy, err := h.svc.UpdatePasswordPolicy(c.Request.Context(), id, c.Query("domainId"), c.Param("policyId"), oci.UpdatePasswordPolicyInput{
		PasswordExpiresAfter:  req.PasswordExpiresAfter,
		MinLength:             req.MinLength,
		NumPasswordsInHistory: req.NumPasswordsInHistory,
	})
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, policy)
}

// @Summary  身份域设置
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Success  200 {object} oci.IdentitySettingInfo
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/identity-settings [get]
func (h *ociConfigHandler) getIdentitySetting(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	setting, err := h.svc.IdentitySetting(c.Request.Context(), id, c.Query("domainId"))
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, setting)
}

// @Summary  更新身份域设置
// @Tags     租户 IAM
// @Param    id path int true "配置 ID"
// @Param    domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param    body body object true "请求体(见接口说明)"
// @Success  200 {object} oci.IdentitySettingInfo
// @Security BearerAuth
// @Router   /api/v1/oci-configs/{id}/identity-settings [put]
func (h *ociConfigHandler) updateIdentitySetting(c *gin.Context) {
	id, ok := pathID(c)
	if !ok {
		return
	}
	var req struct {
		PrimaryEmailRequired *bool `json:"primaryEmailRequired" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	setting, err := h.svc.UpdateIdentitySetting(c.Request.Context(), id, c.Query("domainId"), *req.PrimaryEmailRequired)
	if err != nil {
		respondError(c, err)
		return
	}
	c.JSON(http.StatusOK, setting)
}
