package wecom

import (
	"bytes"
	"context"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/bytedance/sonic"

	"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"
)

// ApprovalDetail 是企微审批详情的权威状态和安全原始 JSON 快照。
type ApprovalDetail struct {
	SPNo     string
	SPStatus int
	Snapshot []byte
}

// ApprovalDetailClient 获取企业微信审批申请详情。
type ApprovalDetailClient struct {
	tokens      DirectoryTokenProvider
	integration TokenIntegrationLog
	httpClient  *http.Client
	baseURL     string
	now         func() time.Time
}

// NewApprovalDetailClient 创建企业微信审批详情客户端。
func NewApprovalDetailClient(tokens DirectoryTokenProvider, integration TokenIntegrationLog, baseURL string, timeout time.Duration) *ApprovalDetailClient {
	if timeout <= 0 {
		timeout = constants.WeComDefaultHTTPTimeout
	}
	return &ApprovalDetailClient{tokens: tokens, integration: integration, httpClient: &http.Client{Timeout: timeout}, baseURL: strings.TrimRight(baseURL, "/"), now: time.Now}
}

// Get 获取审批详情并记录一次真实外呼。
func (c *ApprovalDetailClient) Get(ctx context.Context, applicationID uint, spNo string) (ApprovalDetail, error) {
	token, err := c.tokens.GetAccessToken(ctx, applicationID)
	if err != nil {
		return ApprovalDetail{}, err
	}
	request, err := c.newRequest(ctx, token, spNo)
	if err != nil {
		return ApprovalDetail{}, err
	}
	resourceID := strconv.FormatUint(uint64(applicationID), 10)
	attempt, err := c.integration.Start(ctx, integrationlog.Attempt{
		Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
		Operation: constants.IntegrationOperationWeComApprovalDetail, ResourceType: constants.WeComApprovalInstanceResourceType,
		ResourceID: &resourceID, ExternalID: &spNo, RequestSummary: map[string]any{"application_id": applicationID, "sp_no": spNo},
	})
	if err != nil {
		return ApprovalDetail{}, err
	}
	startedAt := c.now()
	response, err := c.httpClient.Do(request)
	if err != nil {
		return ApprovalDetail{}, c.completeFailure(ctx, attempt.IntegrationID, 0, "request_failed", "企业微信审批详情请求失败", startedAt)
	}
	defer response.Body.Close()
	body, err := io.ReadAll(io.LimitReader(response.Body, constants.WeComDirectoryMaxResponseBodyBytes+1))
	if err != nil || int64(len(body)) > constants.WeComDirectoryMaxResponseBodyBytes {
		return ApprovalDetail{}, c.completeFailure(ctx, attempt.IntegrationID, response.StatusCode, "invalid_response", "企业微信审批详情响应无效", startedAt)
	}
	var payload map[string]any
	if err := sonic.Unmarshal(body, &payload); err != nil {
		return ApprovalDetail{}, c.completeFailure(ctx, attempt.IntegrationID, response.StatusCode, "invalid_response", "企业微信审批详情响应无效", startedAt)
	}
	errCode := numberToInt64(payload["errcode"])
	errMsg, _ := payload["errmsg"].(string)
	info, _ := payload["info"].(map[string]any)
	status := int(numberToInt64(info["sp_status"]))
	if response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusMultipleChoices || errCode != 0 || info == nil {
		return ApprovalDetail{}, c.completeFailure(ctx, attempt.IntegrationID, response.StatusCode, strconv.FormatInt(errCode, 10), errMsg, startedAt)
	}
	snapshot, err := sonic.Marshal(info)
	if err != nil {
		return ApprovalDetail{}, errors.Wrap(errors.CodeInternalError, err, "编码企业微信审批详情快照失败")
	}
	_, err = c.integration.Complete(ctx, attempt.IntegrationID, integrationlog.Completion{
		Result: constants.IntegrationResultSuccess, HTTPStatus: response.StatusCode,
		ProviderCode: strconv.FormatInt(errCode, 10), ProviderMessage: errMsg,
		ResponseSummary: map[string]any{"sp_no": spNo, "sp_status": status}, DurationMS: c.now().Sub(startedAt).Milliseconds(),
	})
	return ApprovalDetail{SPNo: spNo, SPStatus: status, Snapshot: snapshot}, err
}

// newRequest 组装按字符串审批单号查询权威详情的企微请求。
func (c *ApprovalDetailClient) newRequest(ctx context.Context, token, spNo string) (*http.Request, error) {
	endpoint, err := url.Parse(c.baseURL + "/cgi-bin/oa/getapprovaldetail")
	if err != nil || endpoint.Scheme == "" || endpoint.Host == "" {
		return nil, errors.New(errors.CodeWeComCredentialInvalid, "企业微信 API 地址配置无效")
	}
	query := endpoint.Query()
	query.Set("access_token", token)
	endpoint.RawQuery = query.Encode()
	body, err := sonic.Marshal(map[string]string{"sp_no": spNo})
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "编码企业微信审批详情请求失败")
	}
	request, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), bytes.NewReader(body))
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "创建企业微信审批详情请求失败")
	}
	request.Header.Set("Content-Type", "application/json")
	return request, nil
}

// completeFailure 先终结 Integration Log，再向 Asynq 返回可重试的统一错误。
func (c *ApprovalDetailClient) completeFailure(ctx context.Context, integrationID string, status int, providerCode, message string, startedAt time.Time) error {
	if strings.TrimSpace(message) == "" {
		message = "企业微信审批详情接口返回失败"
	}
	_, err := c.integration.Complete(ctx, integrationID, integrationlog.Completion{
		Result: constants.IntegrationResultFailed, HTTPStatus: status, ProviderCode: providerCode,
		ProviderMessage: message, ResponseSummary: map[string]any{"success": false}, DurationMS: c.now().Sub(startedAt).Milliseconds(),
	})
	if err != nil {
		return err
	}
	return errors.New(errors.CodeServiceUnavailable, "获取企业微信审批详情失败")
}
