package control

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// Finance exposes a bounded owner audit projection. This is not a target-table
// readback, and does not replace the DB reader used for financial acceptance.
type financeAPIAudit struct {
	RunID    string  `json:"run_id"`
	Table    string  `json:"target_table"`
	Status   string  `json:"status"`
	Started  string  `json:"started_at"`
	Finished *string `json:"finished_at"`
}

func financeAuditTime(value string) (time.Time, error) {
	for _, layout := range []string{time.RFC3339Nano, "2006-01-02 15:04:05.999999"} {
		if t, err := time.Parse(layout, value); err == nil && !t.IsZero() {
			return t.UTC(), nil
		}
	}
	return time.Time{}, fmt.Errorf("invalid Finance audit timestamp")
}

func (s *ExternalLiveSource) financeAPIHistory(ctx context.Context) (RunBatch, error) {
	u, err := url.Parse(s.config.FinanceHistoryAPIURL)
	if err != nil || u.Scheme != "https" || u.Host == "" || u.User != nil || u.RawQuery != "" || u.Fragment != "" {
		return RunBatch{}, fmt.Errorf("invalid Finance audit API binding")
	}
	u.Path = strings.TrimRight(u.Path, "/") + "/quality/summary"
	u.RawQuery = "limit=100"
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
	if err != nil {
		return RunBatch{}, fmt.Errorf("invalid Finance audit request")
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Cache-Control", "no-cache")
	response, err := s.httpClient.Do(req)
	if err != nil {
		return RunBatch{}, fmt.Errorf("Finance audit API unavailable")
	}
	defer response.Body.Close()
	if response.StatusCode != http.StatusOK {
		return RunBatch{}, fmt.Errorf("Finance audit API HTTP %d", response.StatusCode)
	}
	// Bound the response and discard provider error text/row samples. Neither
	// credentials nor financial payloads are retained in Portal history.
	const maxBytes = 8 << 20
	body, err := io.ReadAll(io.LimitReader(response.Body, maxBytes+1))
	if err != nil || len(body) > maxBytes {
		return RunBatch{}, fmt.Errorf("Finance audit response exceeds read limit")
	}
	var payload struct {
		Service string             `json:"service"`
		Audits  *[]financeAPIAudit `json:"recent_table_audits"`
	}
	if err = json.Unmarshal(body, &payload); err != nil || payload.Service != "data-platform-finance" || payload.Audits == nil || len(*payload.Audits) > 500 {
		return RunBatch{}, fmt.Errorf("invalid Finance audit API contract")
	}
	b := RunBatch{State: CollectionState{Status: "partial", Message: "Finance owner API 最近最多500条逐表审计；无历史分页，非完整30天覆盖；不代表目标读回或业务验收"}}
	seen := map[string]bool{}
	for _, row := range *payload.Audits {
		if row.Table != "salesforce_org" && row.Table != "salesforce_account" && row.Table != "salesforce_order" {
			continue
		}
		started, err := financeAuditTime(row.Started)
		if err != nil || row.RunID == "" || row.Status == "" {
			return RunBatch{}, fmt.Errorf("incomplete Finance audit identity")
		}
		key := row.RunID + ":" + row.Table
		if seen[key] {
			return RunBatch{}, fmt.Errorf("duplicate Finance audit identity")
		}
		seen[key] = true
		run := ProviderRun{Provider: "finance", Task: row.Table, ExternalID: row.RunID, Status: normalizedRunStatus(row.Status), RawStatus: row.Status, StartedAt: started, EventAt: started, Verification: "not_checked", OutputRefs: []string{row.Table}, TimeBasis: "audit_recorded_at", Message: "Finance owner 逐表审计记录时间；独立目标及下游读回未执行"}
		if row.Finished != nil && *row.Finished != "" {
			finished, err := financeAuditTime(*row.Finished)
			if err != nil || finished.Before(started) {
				return RunBatch{}, fmt.Errorf("invalid Finance audit finish time")
			}
			run.FinishedAt, run.EventAt = &finished, finished
		}
		b.Runs = append(b.Runs, run)
		if b.State.CoveredFrom.IsZero() || started.Before(b.State.CoveredFrom) {
			b.State.CoveredFrom = started
		}
	}
	return b, nil
}
