package control

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"regexp"

	"finance-portal/internal/dataplatform/service"
	"finance-portal/model"
)

type DirectRunner struct {
	Finance   service.Service
	Python    string
	ScriptDir string
}

func (r DirectRunner) Run(ctx context.Context, closeRun *CloseRun, definition StepDefinition, attempt *Attempt) (RunnerResult, error) {
	switch definition.Key {
	case "run_monthly_cloud_billing":
		return r.runMonthlyBilling(ctx, closeRun, definition, attempt)
	case "run_cloud_breakdown":
		if r.Finance == nil {
			return RunnerResult{}, fmt.Errorf("Finance database runtime is not configured")
		}
		if err := r.Finance.Cloud().HandleCloudBreakdown(ctx); err != nil {
			return RunnerResult{}, err
		}
	case "sync_order_to_crm":
		return r.runLastMonth(ctx, closeRun, definition, attempt, model.Order)
	case "finalize_revrec":
		return r.runLastMonth(ctx, closeRun, definition, attempt, model.Revrec)
	case "finalize_collection":
		return r.runLastMonth(ctx, closeRun, definition, attempt, model.Collection)
	default:
		return RunnerResult{}, fmt.Errorf("step %s is not owned by the migrated netforce runtime", definition.Key)
	}
	return directReceipt(closeRun, definition, attempt), nil
}

func (r DirectRunner) Reconcile(context.Context, *CloseRun, StepDefinition, *Attempt) (RunnerResult, error) {
	return RunnerResult{}, fmt.Errorf("direct runtime has no unresolved external run; inspect the persisted attempt receipt")
}

func (r DirectRunner) runLastMonth(ctx context.Context, closeRun *CloseRun, definition StepDefinition, attempt *Attempt, entityType int) (RunnerResult, error) {
	if r.Finance == nil {
		return RunnerResult{}, fmt.Errorf("Finance database and CRM runtime are not configured")
	}
	request := model.SfReqBody{Type: entityType, BillMonth: closeRun.BillMonth}
	switch entityType {
	case model.Order:
		request.Types = "order"
	case model.Revrec:
		request.Types = "revrec"
	case model.Collection:
		request.Types = "collection"
	}
	if err := request.ValidateLastMonthBatchScope(); err != nil {
		return RunnerResult{}, err
	}
	if err := r.Finance.Salesforce().RunLastInvoiceMonth(ctx, request); err != nil {
		return RunnerResult{}, err
	}
	return directReceipt(closeRun, definition, attempt), nil
}

func (r DirectRunner) runMonthlyBilling(ctx context.Context, closeRun *CloseRun, definition StepDefinition, attempt *Attempt) (RunnerResult, error) {
	frozen := closeRun.Steps["freeze_billing_inputs"]
	if frozen == nil || frozen.Execution != ExecutionSucceeded || frozen.Verification != VerificationPassed {
		return RunnerResult{}, fmt.Errorf("verified frozen billing inputs are required")
	}
	var manifest struct {
		URI        string `json:"uri"`
		Generation string `json:"generation"`
		SHA256     string `json:"sha256"`
	}
	encoded, err := json.Marshal(frozen.Receipt["input_manifest"])
	if err != nil || json.Unmarshal(encoded, &manifest) != nil || manifest.URI == "" ||
		!regexp.MustCompile(`^[1-9][0-9]{0,19}$`).MatchString(manifest.Generation) ||
		!regexp.MustCompile(`^[a-f0-9]{64}$`).MatchString(manifest.SHA256) {
		return RunnerResult{}, fmt.Errorf("frozen input manifest identity is unbound")
	}
	python := r.Python
	if python == "" {
		python = "python3"
	}
	script := r.ScriptDir
	if script == "" {
		script = "script/finance_portal/monthly_billing.py"
	}
	command := exec.CommandContext(ctx, python, script,
		"--bill-month", closeRun.BillMonth,
		"--mode", closeRun.Mode,
		"--run-id", closeRun.ID,
		"--attempt-id", attempt.ID,
		"--definition-hash", closeRun.DefinitionHash,
		"--input-manifest-uri", manifest.URI,
		"--input-manifest-generation", manifest.Generation,
		"--input-manifest-sha256", manifest.SHA256,
	)
	command.Env = os.Environ()
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	command.Stdout = &stdout
	command.Stderr = &stderr
	if err := command.Run(); err != nil {
		return RunnerResult{}, fmt.Errorf("monthly billing failed; inspect sanitized worker diagnostics (%T)", err)
	}
	result := directReceipt(closeRun, definition, attempt)
	var worker map[string]any
	if err := json.Unmarshal(stdout.Bytes(), &worker); err != nil {
		return RunnerResult{}, fmt.Errorf("monthly worker did not return a valid receipt")
	}
	for key, expected := range map[string]string{"run_id": closeRun.ID, "attempt_id": attempt.ID, "bill_month": closeRun.BillMonth, "mode": closeRun.Mode, "definition_hash": closeRun.DefinitionHash} {
		if worker[key] != expected {
			return RunnerResult{}, fmt.Errorf("monthly worker receipt scope mismatch")
		}
	}
	result.ExternalRunID = "portal-billing-" + attempt.ID
	result.Receipt["input_manifest"] = manifest
	result.Receipt["attempt_id"] = attempt.ID
	result.Receipt["verification"] = "not_checked"
	for _, key := range []string{"run_id", "bill_month", "mode", "order_snapshot_date"} {
		if value, ok := worker[key].(string); ok {
			result.Receipt[key] = value
		}
	}
	if outputs, ok := worker["outputs"].(map[string]any); ok {
		safe := map[string]any{}
		for _, key := range []string{"collections", "orders", "collection_job", "order_job"} {
			if value, ok := outputs[key].(string); ok {
				safe[key] = value
			}
		}
		result.Receipt["outputs"] = safe
	}
	return result, nil
}

func directReceipt(closeRun *CloseRun, definition StepDefinition, attempt *Attempt) RunnerResult {
	return RunnerResult{
		ExternalRunID: "portal-" + attempt.ID[:8],
		Receipt: map[string]any{
			"runtime":         "finance-portal",
			"bill_month":      closeRun.BillMonth,
			"mode":            closeRun.Mode,
			"scope":           definition.Scope,
			"definition_hash": closeRun.DefinitionHash,
			"idempotency_key": attempt.IdempotencyKey,
		},
	}
}
