package org

import (
	"context"
	"errors"
	"net/http"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/knowledgeqa/protocol"
)

type organizationKnowledgeQAPolicyResponse struct {
	Policy protocol.OrganizationPolicy `json:"policy"`
	Status string                      `json:"status"`
}

func (handler *KnowledgeQAPolicyHandler) Get(r api.AuthenticatedRequest) (api.Response, error) {
	organizationID, err := handler.requireKnowledgeQAPolicyAdmin(r)
	if err != nil {
		return api.Response{}, err
	}
	return handler.loadKnowledgeQAPolicyResponse(r.Context(), organizationID)
}

func (handler *KnowledgeQAPolicyHandler) Metrics(r api.AuthenticatedRequest) (api.Response, error) {
	organizationID, err := handler.requireKnowledgeQAPolicyAdmin(r)
	if err != nil {
		return api.Response{}, err
	}
	if handler.knowledgeQAPolicies == nil {
		return api.Response{}, api.NewHTTPErrorWithCode(http.StatusServiceUnavailable, "Knowledge Q&A policy is unavailable", "knowledge_qa_policy_unavailable")
	}
	metrics, err := handler.knowledgeQAPolicies.LoadPolicyMetrics(r.Context(), organizationID)
	if err != nil {
		return api.Response{}, mapOrganizationKnowledgeQAPolicyError(err)
	}
	return api.OK(metrics), nil
}

func (handler *KnowledgeQAPolicyHandler) Put(r api.AuthenticatedJSON[protocol.OrganizationPolicyUpdate]) (api.Response, error) {
	organizationID, err := handler.requireKnowledgeQAPolicyAdmin(r.AuthenticatedRequest)
	if err != nil {
		return api.Response{}, err
	}
	if handler.knowledgeQAPolicies == nil {
		return api.Response{}, api.NewHTTPErrorWithCode(http.StatusServiceUnavailable, "Knowledge Q&A policy is unavailable", "knowledge_qa_policy_unavailable")
	}
	if _, err := handler.knowledgeQAPolicies.UpdateOrganizationPolicy(r.Context(), r.UserID(), organizationID, r.Body, time.Now().UTC()); err != nil {
		return api.Response{}, mapOrganizationKnowledgeQAPolicyError(err)
	}
	return handler.loadKnowledgeQAPolicyResponse(r.Context(), organizationID)
}

func (handler *KnowledgeQAPolicyHandler) requireKnowledgeQAPolicyAdmin(r api.AuthenticatedRequest) (string, error) {
	organizationID := strings.TrimSpace(r.Gin.Param("orgId"))
	if organizationID == "" {
		return "", api.NewHTTPErrorWithCode(http.StatusBadRequest, "orgId is required", "knowledge_qa_policy_invalid")
	}
	organizations, ok := handler.organizationProvider()
	if !ok {
		return "", api.NewHTTPErrorWithCode(http.StatusServiceUnavailable, "Organization provider is unavailable", "knowledge_qa_policy_unavailable")
	}
	if err := organizations.RequireOrganizationAdmin(r.Context(), r.UserID(), organizationID); err != nil {
		if isOrganizationProviderForbidden(err) {
			return "", api.NewHTTPErrorWithCode(http.StatusForbidden, "Knowledge Q&A policy requires organization administrator access", "knowledge_qa_policy_forbidden")
		}
		return "", err
	}
	return organizationID, nil
}

func (handler *KnowledgeQAPolicyHandler) loadKnowledgeQAPolicyResponse(ctx context.Context, organizationID string) (api.Response, error) {
	if handler.knowledgeQAPolicies == nil {
		return api.Response{}, api.NewHTTPErrorWithCode(http.StatusServiceUnavailable, "Knowledge Q&A policy is unavailable", "knowledge_qa_policy_unavailable")
	}
	policy, err := handler.knowledgeQAPolicies.LoadOrganizationPolicy(ctx, organizationID)
	if err != nil {
		return api.Response{}, mapOrganizationKnowledgeQAPolicyError(err)
	}
	response := organizationKnowledgeQAPolicyResponse{
		Policy: policy, Status: "disabled",
	}
	if policy.Enabled {
		response.Status = "enabled"
	}
	return api.OK(response), nil
}

func mapOrganizationKnowledgeQAPolicyError(err error) error {
	switch {
	case errors.Is(err, protocol.ErrPolicyUnavailable):
		return api.NewHTTPErrorWithCodeAndCause(http.StatusServiceUnavailable, "Knowledge Q&A policy is unavailable", "knowledge_qa_policy_unavailable", err)
	case errors.Is(err, protocol.ErrPolicyInvalid):
		return api.NewHTTPErrorWithCodeAndCause(http.StatusBadRequest, "Knowledge Q&A policy is invalid", "knowledge_qa_policy_invalid", err)
	default:
		return err
	}
}
