package wecom

import (
	"context"
	"strings"
	"time"

	"github.com/bytedance/sonic"
	"github.com/hibiken/asynq"

	approvalapp "github.com/break/junhong_cmp_fiber/internal/application/approval"
	"github.com/break/junhong_cmp_fiber/internal/infrastructure/integrationlog"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
)

// ApprovalDetailTaskHandler 拉取企微审批详情并翻译为现有标准决策。
type ApprovalDetailTaskHandler struct {
	details     *ApprovalDetailClient
	contexts    *ApprovalContextRepository
	decisions   *approvalapp.SyncDecisionService
	integration TokenIntegrationLog
}

// NewApprovalDetailTaskHandler 创建企业微信审批详情同步任务 Handler。
func NewApprovalDetailTaskHandler(details *ApprovalDetailClient, contexts *ApprovalContextRepository, decisions *approvalapp.SyncDecisionService, integration TokenIntegrationLog) *ApprovalDetailTaskHandler {
	return &ApprovalDetailTaskHandler{details: details, contexts: contexts, decisions: decisions, integration: integration}
}

// Handle 处理回调或后续轮询提交的详情同步任务。
func (h *ApprovalDetailTaskHandler) Handle(ctx context.Context, task *asynq.Task) error {
	if h == nil || h.details == nil || h.contexts == nil || h.decisions == nil || h.integration == nil {
		return errors.New(errors.CodeServiceUnavailable, "企业微信审批详情同步任务未配置")
	}
	var payload ApprovalDetailSyncTask
	if err := sonic.Unmarshal(task.Payload(), &payload); err != nil || payload.ApplicationID == 0 || strings.TrimSpace(payload.SPNo) == "" {
		return errors.New(errors.CodeInvalidParam, "企业微信审批详情同步任务载荷无效")
	}
	if !validApprovalSyncSource(payload.Source) {
		return errors.New(errors.CodeInvalidParam, "企业微信审批详情同步来源无效")
	}
	detail, err := h.details.Get(ctx, payload.ApplicationID, payload.SPNo)
	if err != nil {
		return err
	}
	record, err := h.contexts.FindBySPNo(ctx, payload.ApplicationID, payload.SPNo)
	if err != nil {
		return err
	}
	if record == nil {
		record, err = h.recoverUnknownCallback(ctx, payload, detail)
		if err != nil {
			return err
		}
		if record == nil {
			return h.completeIgnoredCallback(ctx, payload)
		}
	}
	if err := h.contexts.SaveLatestDetail(ctx, record.Instance.ID, detail.SPStatus, detail.Snapshot); err != nil {
		return err
	}
	decisions := weComDecisions(detail.SPStatus)
	for _, decision := range decisions {
		if _, err := h.decisions.Execute(ctx, approvalapp.SyncDecisionCommand{
			InstanceID: record.Instance.ID, Decision: decision, DecisionSnapshot: detail.Snapshot, Source: payload.Source,
		}); err != nil {
			return err
		}
	}
	if strings.TrimSpace(payload.IntegrationID) != "" {
		_, err = h.integration.Complete(ctx, payload.IntegrationID, integrationlog.Completion{
			Result: constants.IntegrationResultCompleted, ProviderCode: "processed",
			ProviderMessage: "企业微信审批回调已完成权威详情同步",
			ResponseSummary: map[string]any{"sp_no": payload.SPNo, "sp_status": detail.SPStatus, "decisions": decisions},
			DurationMS:      0, StateChanged: len(decisions) > 0,
		})
	}
	return err
}

func (h *ApprovalDetailTaskHandler) recoverUnknownCallback(ctx context.Context, payload ApprovalDetailSyncTask, detail ApprovalDetail) (*ApprovalSubmissionRecord, error) {
	if payload.Source != constants.ApprovalSyncSourceCallback {
		return nil, nil
	}
	fingerprint := approvalDetailFingerprint(detail.Snapshot)
	candidate, err := h.contexts.FindUniqueUnknownByFingerprint(
		ctx, payload.ApplicationID, fingerprint.TemplateID, fingerprint.CreatorUserID, fingerprint.SubmittedAt,
	)
	if err != nil || candidate == nil {
		return nil, err
	}
	recovered, err := h.contexts.RecoverSubmitted(ctx, candidate.InstanceID, payload.SPNo)
	if err != nil || !recovered {
		return nil, err
	}
	return h.contexts.Get(ctx, candidate.InstanceID)
}

func (h *ApprovalDetailTaskHandler) completeIgnoredCallback(ctx context.Context, payload ApprovalDetailSyncTask) error {
	if strings.TrimSpace(payload.IntegrationID) == "" {
		return nil
	}
	_, err := h.integration.Complete(ctx, payload.IntegrationID, integrationlog.Completion{
		Result: constants.IntegrationResultIgnored, ProviderCode: "unrelated_approval",
		ProviderMessage: "企业微信审批单未关联本系统业务，已忽略",
		ResponseSummary: map[string]any{"sp_no": payload.SPNo, "ignored": true},
	})
	return err
}

type approvalFingerprint struct {
	TemplateID    string
	CreatorUserID string
	SubmittedAt   time.Time
}

func approvalDetailFingerprint(snapshot []byte) approvalFingerprint {
	var value struct {
		TemplateID string `json:"template_id"`
		ApplyTime  int64  `json:"apply_time"`
		Applyer    struct {
			UserID string `json:"userid"`
		} `json:"applyer"`
	}
	if sonic.Unmarshal(snapshot, &value) != nil || value.ApplyTime <= 0 {
		return approvalFingerprint{}
	}
	return approvalFingerprint{
		TemplateID: strings.TrimSpace(value.TemplateID), CreatorUserID: strings.TrimSpace(value.Applyer.UserID),
		SubmittedAt: time.Unix(value.ApplyTime, 0).UTC(),
	}
}

func validApprovalSyncSource(source string) bool {
	switch source {
	case constants.ApprovalSyncSourceCallback, constants.ApprovalSyncSourcePolling, constants.ApprovalSyncSourceManual:
		return true
	default:
		return false
	}
}

// weComDecisions 只翻译现有审批核心支持的企微标准终态；通过后撤销按领域允许顺序补齐两个事实。
func weComDecisions(status int) []string {
	switch status {
	case 2:
		return []string{constants.ApprovalDecisionApproved}
	case 3:
		return []string{constants.ApprovalDecisionRejected}
	case 4:
		return []string{constants.ApprovalDecisionCancelled}
	case 6:
		return []string{constants.ApprovalDecisionApproved, constants.ApprovalDecisionRevokedAfterApproved}
	case 7:
		return []string{constants.ApprovalDecisionDeleted}
	default:
		return nil
	}
}
