package control

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"path"
	"strings"
	"time"

	"google.golang.org/api/googleapi"
	runapi "google.golang.org/api/run/v2"
)

// These exact owner jobs were verified in gcp-digital-bi/us-west2. No list across
// the account and no invocation, override, cancellation or IAM action is exposed.
func crmJobBinding(provider string) (string, string, error) {
	switch provider {
	case "crm_extract":
		return "projects/gcp-digital-bi/locations/us-west2/jobs/pingcap-nexuscrm-extract", "crm_extract", nil
	case "crm_load_job":
		return "projects/gcp-digital-bi/locations/us-west2/jobs/pingcap-nexuscrm-load", "crm_load", nil
	default:
		return "", "", fmt.Errorf("unknown CRM execution source")
	}
}

type crmExecutionCursor struct {
	PageToken string
	Pages     int
	From      time.Time
}

func (s *ExternalLiveSource) crmJobHistory(ctx context.Context, previous CollectionState, provider string) (RunBatch, error) {
	job, task, err := crmJobBinding(provider)
	if err != nil {
		return RunBatch{}, err
	}
	if s.config.CRMControlDataset != "gcp-digital-bi.nexuscrm_control" {
		return RunBatch{State: CollectionState{Status: "unconfigured", Message: "当前CRM审计源未绑定这两个已验证的执行Job；不推测其他环境"}}, nil
	}
	if s.runJobs == nil {
		return RunBatch{}, fmt.Errorf("Cloud Run execution reader unavailable")
	}
	now := time.Now().UTC()
	cursor := crmExecutionCursor{From: now.AddDate(0, 0, -30)}
	if previous.Cursor != "" {
		if json.Unmarshal([]byte(previous.Cursor), &cursor) != nil || cursor.Pages < 1 || cursor.Pages > 4 || cursor.PageToken == "" || cursor.From.Before(now.AddDate(0, 0, -31)) || cursor.From.After(now) {
			return RunBatch{State: CollectionState{Status: "unavailable", Message: "CRM执行游标过期或无效；保留历史，下轮重扫"}}, nil
		}
	}
	response, err := s.runJobs.Projects.Locations.Jobs.Executions.List(job).PageSize(100).PageToken(cursor.PageToken).Fields("executions(name,job,createTime,startTime,completionTime,conditions(type,state,executionReason,lastTransitionTime),failedCount,succeededCount,cancelledCount),nextPageToken").Context(ctx).Do()
	if err != nil {
		var apiErr *googleapi.Error
		if cursor.PageToken != "" && errors.As(err, &apiErr) && apiErr.Code == 400 {
			return RunBatch{State: CollectionState{Status: "unavailable", Message: "CRM执行分页令牌被拒绝；下轮重扫，旧事实保留"}}, nil
		}
		return RunBatch{}, fmt.Errorf("CRM job execution read failed")
	}
	if len(response.Executions) > 100 {
		return RunBatch{}, fmt.Errorf("CRM job execution response exceeds limit")
	}
	b := RunBatch{State: CollectionState{Status: "partial", CoveredFrom: cursor.From, Message: "Cloud Run原始执行回执；近30天、每轮最多500条，受provider保留影响；进程成功不代表产物更新或业务验收"}}
	for _, entry := range response.Executions {
		run, err := crmExecutionRun(entry, job, task, provider)
		if err != nil {
			return RunBatch{}, err
		}
		if run.StartedAt.Before(cursor.From) && run.Status != "running" && run.Status != "pending" {
			continue
		}
		b.Runs = append(b.Runs, run)
	}
	if response.NextPageToken != "" && cursor.Pages < 4 {
		cursor.PageToken = response.NextPageToken
		cursor.Pages++
		encoded, _ := json.Marshal(cursor)
		b.State.Cursor = string(encoded)
	}
	return b, nil
}

func crmExecutionRun(entry *runapi.GoogleCloudRunV2Execution, job, task, provider string) (ProviderRun, error) {
	prefix := job + "/executions/"
	if entry == nil || !strings.HasPrefix(entry.Name, prefix) || strings.TrimPrefix(entry.Name, prefix) == "" || strings.Contains(strings.TrimPrefix(entry.Name, prefix), "/") || (entry.Job != path.Base(job) && entry.Job != job) {
		return ProviderRun{}, fmt.Errorf("CRM execution identity mismatch")
	}
	start := parseTimeString(entry.StartTime)
	timeBasis := ""
	if start == nil {
		start = parseTimeString(entry.CreateTime)
		timeBasis = "created_at"
	}
	if start == nil {
		return ProviderRun{}, fmt.Errorf("CRM execution has no valid timestamp")
	}
	run := ProviderRun{Provider: provider, Task: task, ExternalID: entry.Name, Status: "unknown", RawStatus: "condition_missing", Verification: "not_checked", StartedAt: *start, EventAt: *start, TimeBasis: timeBasis, Message: "Cloud Run提取执行回执；实际表范围与manifest尚未关联，不能代替产物验证"}
	if provider == "crm_load_job" {
		run.Message = "Cloud Run加载进程回执；成功可能没有新manifest可加载，不代表表已更新或业务验收"
	}
	if end := parseTimeString(entry.CompletionTime); end != nil {
		run.FinishedAt = end
		if end.After(run.EventAt) {
			run.EventAt = *end
		}
	}
	completed := 0
	for _, condition := range entry.Conditions {
		if condition == nil {
			continue
		}
		if t := parseTimeString(condition.LastTransitionTime); t != nil && t.After(run.EventAt) {
			run.EventAt = *t
		}
		if condition.Type != "Completed" {
			continue
		}
		completed++
		run.RawStatus = condition.State
		switch condition.State {
		case "CONDITION_SUCCEEDED":
			run.Status = "succeeded"
		case "CONDITION_FAILED":
			run.Status = "failed"
			if condition.ExecutionReason == "CANCELLED" {
				run.Status = "cancelled"
			}
		case "CONDITION_PENDING", "CONDITION_RECONCILING":
			run.Status = "running"
			if timeBasis == "created_at" {
				run.Status = "pending"
			}
		default:
			run.RawStatus = "condition_unknown"
		}
	}
	if completed > 1 {
		return ProviderRun{}, fmt.Errorf("ambiguous CRM completion conditions")
	}
	if run.Status == "succeeded" && (entry.FailedCount > 0 || entry.CancelledCount > 0) {
		return ProviderRun{}, fmt.Errorf("inconsistent CRM execution outcome")
	}
	return run, nil
}
