package cmd

import (
	"encoding/json"
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/tidbcloud/controlplane9/internal/cluster"
)

var statusO11YProducts = []string{"starter", "premium", "essential_v2", "dedicated"}

type statusO11YPlatformEvidence struct {
	Status              string `json:"status"`
	ClusterStatus       string `json:"cluster_status"`
	ClusterID           string `json:"cluster_id"`
	ActiveClusters      int    `json:"active_clusters_before_gateway"`
	CleanupPending      bool   `json:"cleanup_pending"`
	VMCluster           string `json:"vmcluster"`
	VMAccountID         string `json:"vm_account_id"`
	VMProjectID         string `json:"vm_project_id"`
	DNSName             string `json:"dns_name"`
	EndpointServiceName string `json:"endpoint_service_name"`
}

type statusO11YGatewayEvidence struct {
	Status                      string `json:"status"`
	GlobalAPIStatus             int    `json:"global_api_status"`
	MetricsWriteStatus          int    `json:"metrics_write_status"`
	MetricsQueryStatus          int    `json:"metrics_query_status"`
	MetricsMarker               string `json:"metrics_marker"`
	PrivateWritePublicALBStatus int    `json:"private_write_public_alb_status"`
	PrivateWritePublicNLBStatus int    `json:"private_write_public_nlb_status"`
	ActiveClustersAfterDelete   *int   `json:"active_clusters_after_delete"`
}

type statusO11YProductDimension struct {
	Status       string `json:"status"`
	EvidencePath string `json:"evidencePath"`
}

type statusO11YProductEvidence struct {
	Product             string                     `json:"product"`
	Status              string                     `json:"status"`
	RoutingMapping      statusO11YProductDimension `json:"routingMapping"`
	ACS                 statusO11YProductDimension `json:"acs"`
	AgentCR             statusO11YProductDimension `json:"agentCR"`
	AgentWorkload       statusO11YProductDimension `json:"agentWorkload"`
	MetricsWriteQuery   statusO11YProductDimension `json:"metricsWriteQuery"`
	NamespaceNegative   statusO11YProductDimension `json:"namespaceNegative"`
	InterruptedRecovery statusO11YProductDimension `json:"interruptedRecovery"`
	Idempotency         statusO11YProductDimension `json:"idempotency"`
	Cleanup             statusO11YProductCleanup   `json:"cleanup"`
	LogsBackend         string                     `json:"logsBackend"`
	Alerts              string                     `json:"alerts"`
	DrHouse             string                     `json:"drHouse"`
}

type statusO11YProductCleanup struct {
	Status                    string `json:"status"`
	EvidencePath              string `json:"evidencePath"`
	AgentCRsAfterDelete       *int   `json:"agentCRsAfterDelete"`
	AgentWorkloadsAfterDelete *int   `json:"agentWorkloadsAfterDelete"`
	MappingsAfterDelete       *int   `json:"mappingsAfterDelete"`
}

type statusO11YProductSummary struct {
	CP9Session   string          `json:"cp9Session"`
	CP9CreatedAt time.Time       `json:"cp9CreatedAt"`
	O11Y         json.RawMessage `json:"o11y"`
}

type statusO11YProductCandidate struct {
	evidence statusO11YProductEvidence
	path     string
	modTime  time.Time
	err      error
}

func statusO11YFromState(stateDir string, state *cluster.State) *cluster.StatusO11YLayer {
	if state == nil || strings.TrimSpace(state.Persona) != "dev-full" {
		return nil
	}
	layer := &cluster.StatusO11YLayer{
		Status:              "not_collected",
		Platform:            statusO11YDimension("not_collected", "", "platform readiness evidence not found"),
		RoutingMapping:      map[string]cluster.StatusO11YDimension{},
		ACS:                 map[string]cluster.StatusO11YDimension{},
		AgentCR:             map[string]cluster.StatusO11YDimension{},
		AgentWorkload:       map[string]cluster.StatusO11YDimension{},
		MetricsWriteQuery:   map[string]cluster.StatusO11YDimension{},
		NamespaceNegative:   map[string]cluster.StatusO11YDimension{},
		InterruptedRecovery: map[string]cluster.StatusO11YDimension{},
		Idempotency:         map[string]cluster.StatusO11YDimension{},
		Cleanup:             map[string]cluster.StatusO11YDimension{},
		PublicWriteNegative: statusO11YDimension("not_collected", "", "gateway readiness evidence not found"),
		LogsBackend:         "not_deployed",
		Alerts:              "not_deployed",
		DrHouse:             "not_deployed",
	}

	hasEvidence := false
	hasFailure := false
	evidenceDir := filepath.Join(stateDir, "tilt", "reports", "evidence")
	platformPath := filepath.Join(evidenceDir, "o11y-platform-readiness.json")
	if found, passed := projectStatusO11YPlatform(layer, platformPath); found {
		hasEvidence = true
		hasFailure = hasFailure || !passed
	}
	gatewayPath := filepath.Join(evidenceDir, "o11y-gateway-readiness.json")
	if found, passed := projectStatusO11YGateway(layer, gatewayPath); found {
		hasEvidence = true
		hasFailure = hasFailure || !passed
	}

	products, invalidProduct := latestStatusO11YProducts(stateDir, state)
	for product, candidate := range products {
		hasEvidence = true
		passed := projectStatusO11YProduct(layer, product, candidate)
		hasFailure = hasFailure || !passed
	}
	hasFailure = hasFailure || invalidProduct

	switch {
	case hasFailure:
		layer.Status = "failed"
		layer.Message = "one or more persisted O11Y proof contracts are invalid or failed"
	case !hasEvidence:
		layer.Message = "no O11Y proof evidence found for this session"
	case statusO11YComplete(layer):
		layer.Status = "passed"
		layer.Message = "shared platform and all four product O11Y proof contracts passed"
	default:
		layer.Status = "partial"
		layer.Message = fmt.Sprintf("shared or product O11Y proof is incomplete (%d/%d products)", len(products), len(statusO11YProducts))
	}
	return layer
}

func projectStatusO11YPlatform(layer *cluster.StatusO11YLayer, path string) (found, passed bool) {
	var evidence statusO11YPlatformEvidence
	found, err := readStatusO11YEvidence(path, &evidence)
	if !found {
		return false, false
	}
	if err != nil {
		layer.Platform = statusO11YDimension("invalid", path, err.Error())
		layer.RoutingMapping["shared"] = layer.Platform
		return true, false
	}
	platformPassed := evidence.VMCluster == "operational"
	routingPassed := evidence.ClusterStatus == "ACTIVE" && strings.TrimSpace(evidence.ClusterID) != "" &&
		evidence.ActiveClusters == 1 && evidence.CleanupPending && strings.TrimSpace(evidence.VMAccountID) != "" &&
		strings.TrimSpace(evidence.VMProjectID) != "" && strings.TrimSpace(evidence.DNSName) != "" &&
		strings.TrimSpace(evidence.EndpointServiceName) != ""
	layer.Platform = statusO11YPassedDimension(platformPassed, path, "shared VM platform did not become operational")
	layer.RoutingMapping["shared"] = statusO11YPassedDimension(routingPassed, path, "shared GS/RS mapping contract did not pass")
	return true, evidence.Status == "passed" && platformPassed && routingPassed
}

func projectStatusO11YGateway(layer *cluster.StatusO11YLayer, path string) (found, passed bool) {
	var evidence statusO11YGatewayEvidence
	found, err := readStatusO11YEvidence(path, &evidence)
	if !found {
		return false, false
	}
	if err != nil {
		dimension := statusO11YDimension("invalid", path, err.Error())
		layer.MetricsWriteQuery["shared"] = dimension
		layer.PublicWriteNegative = dimension
		layer.Cleanup["shared"] = dimension
		return true, false
	}
	metricsPassed := evidence.Status == "passed" && evidence.GlobalAPIStatus == 200 &&
		(evidence.MetricsWriteStatus == 200 || evidence.MetricsWriteStatus == 204) &&
		evidence.MetricsQueryStatus == 200 && evidence.MetricsMarker == "cp9_o11y_gateway_ready"
	publicWritePassed := evidence.PrivateWritePublicALBStatus == 404 && evidence.PrivateWritePublicNLBStatus == 404
	cleanupPassed := evidence.ActiveClustersAfterDelete != nil && *evidence.ActiveClustersAfterDelete == 0
	layer.MetricsWriteQuery["shared"] = statusO11YPassedDimension(metricsPassed, path, "shared metrics write/query contract did not pass")
	layer.PublicWriteNegative = statusO11YPassedDimension(
		publicWritePassed,
		path,
		"private write route was not absent from both public entrypoints",
	)
	layer.Cleanup["shared"] = statusO11YPassedDimension(cleanupPassed, path, "shared mapping cleanup did not reach zero")
	return true, metricsPassed && publicWritePassed && cleanupPassed
}

func projectStatusO11YProduct(layer *cluster.StatusO11YLayer, product string, candidate *statusO11YProductCandidate) bool {
	if candidate.err != nil {
		dimension := statusO11YDimension("invalid", candidate.path, candidate.err.Error())
		layer.RoutingMapping[product] = dimension
		layer.ACS[product] = dimension
		layer.AgentCR[product] = dimension
		layer.AgentWorkload[product] = dimension
		layer.MetricsWriteQuery[product] = dimension
		layer.NamespaceNegative[product] = dimension
		layer.InterruptedRecovery[product] = dimension
		layer.Idempotency[product] = dimension
		layer.Cleanup[product] = dimension
		layer.LogsBackend = "invalid"
		layer.Alerts = "invalid"
		layer.DrHouse = "invalid"
		return false
	}
	evidence := candidate.evidence
	project := func(target map[string]cluster.StatusO11YDimension, dimension statusO11YProductDimension) bool {
		passed := dimension.Status == "passed" && statusO11YEvidenceFile(candidate.path, dimension.EvidencePath)
		target[product] = statusO11YPassedDimension(passed, candidate.path, "product proof dimension did not pass")
		return passed
	}
	passed := project(layer.RoutingMapping, evidence.RoutingMapping)
	passed = project(layer.ACS, evidence.ACS) && passed
	passed = project(layer.AgentCR, evidence.AgentCR) && passed
	passed = project(layer.AgentWorkload, evidence.AgentWorkload) && passed
	passed = project(layer.MetricsWriteQuery, evidence.MetricsWriteQuery) && passed
	passed = project(layer.NamespaceNegative, evidence.NamespaceNegative) && passed
	passed = project(layer.InterruptedRecovery, evidence.InterruptedRecovery) && passed
	passed = project(layer.Idempotency, evidence.Idempotency) && passed
	cleanupPassed := statusO11YCleanupPassed(product, candidate.path, evidence.Cleanup)
	layer.Cleanup[product] = statusO11YPassedDimension(cleanupPassed, candidate.path, "product cleanup contract did not pass")
	passed = cleanupPassed && passed
	backendsPassed := evidence.LogsBackend == "not_deployed" && evidence.Alerts == "not_deployed" && evidence.DrHouse == "not_deployed"
	if evidence.LogsBackend != "not_deployed" {
		layer.LogsBackend = "invalid"
	}
	if evidence.Alerts != "not_deployed" {
		layer.Alerts = "invalid"
	}
	if evidence.DrHouse != "not_deployed" {
		layer.DrHouse = "invalid"
	}
	return evidence.Status == "passed" && passed && backendsPassed
}

func statusO11YCleanupPassed(product, summaryPath string, cleanup statusO11YProductCleanup) bool {
	if cleanup.Status != "passed" || cleanup.AgentCRsAfterDelete == nil || cleanup.AgentWorkloadsAfterDelete == nil ||
		cleanup.MappingsAfterDelete == nil || !statusO11YEvidenceFile(summaryPath, cleanup.EvidencePath) {
		return false
	}
	if product == "starter" {
		return *cleanup.AgentCRsAfterDelete == 2 && *cleanup.AgentWorkloadsAfterDelete > 0 && *cleanup.MappingsAfterDelete > 0
	}
	return *cleanup.AgentCRsAfterDelete == 0 && *cleanup.AgentWorkloadsAfterDelete == 0 && *cleanup.MappingsAfterDelete == 0
}

func statusO11YEvidenceFile(summaryPath, evidencePath string) bool {
	evidencePath = filepath.Clean(strings.TrimSpace(evidencePath))
	if evidencePath == "." || filepath.IsAbs(evidencePath) {
		return false
	}
	rooted, err := os.OpenRoot(filepath.Dir(summaryPath))
	if err != nil {
		return false
	}
	defer rooted.Close()
	info, err := rooted.Stat(evidencePath)
	return err == nil && info.Mode().IsRegular() && info.Size() > 0
}

func latestStatusO11YProducts(stateDir string, state *cluster.State) (map[string]*statusO11YProductCandidate, bool) {
	products := map[string]*statusO11YProductCandidate{}
	repoRoot := statusO11YRepoRoot(stateDir)
	if repoRoot == "" {
		return products, false
	}
	sessionName := firstNonEmptyString(state.SessionName, state.ClusterName, state.SessionID)
	invalid := false
	for _, artifact := range []string{"starter-openapi", "premium-openapi", "dedicated-openapi"} {
		root := filepath.Join(repoRoot, "artifacts", artifact)
		rooted, err := os.OpenRoot(root)
		if err != nil {
			continue
		}
		paths, _ := fs.Glob(rooted.FS(), "*/summary.json")
		for _, path := range paths {
			var summary statusO11YProductSummary
			data, err := rooted.ReadFile(path)
			if err != nil || json.Unmarshal(data, &summary) != nil {
				invalid = true
				continue
			}
			if strings.TrimSpace(summary.CP9Session) != sessionName ||
				!summary.CP9CreatedAt.Equal(state.CreatedAt) || len(summary.O11Y) == 0 {
				continue
			}
			var identity struct {
				Product string `json:"product"`
			}
			if json.Unmarshal(summary.O11Y, &identity) != nil {
				invalid = true
				continue
			}
			product := strings.TrimSpace(identity.Product)
			if !validStatusO11YArtifactProduct(artifact, product) {
				invalid = true
				continue
			}
			info, _ := fs.Stat(rooted.FS(), path)
			candidate := &statusO11YProductCandidate{path: filepath.Join(root, path)}
			candidate.err = json.Unmarshal(summary.O11Y, &candidate.evidence)
			if info != nil {
				candidate.modTime = info.ModTime()
			}
			if current, ok := products[product]; !ok || candidate.modTime.After(current.modTime) ||
				(candidate.modTime.Equal(current.modTime) && candidate.path > current.path) {
				products[product] = candidate
			}
		}
		_ = rooted.Close()
	}
	return products, invalid
}

func statusO11YRepoRoot(stateDir string) string {
	abs, err := filepath.Abs(stateDir)
	if err != nil {
		return ""
	}
	stateRoot := filepath.Dir(abs)
	if filepath.Base(stateRoot) != cluster.DefaultStateDir {
		return ""
	}
	return filepath.Dir(stateRoot)
}

func readStatusO11YEvidence(path string, target any) (bool, error) {
	data, err := os.ReadFile(path)
	if os.IsNotExist(err) {
		return false, nil
	}
	if err != nil {
		return true, fmt.Errorf("read evidence: %w", err)
	}
	if err := json.Unmarshal(data, target); err != nil {
		return true, fmt.Errorf("decode evidence: %w", err)
	}
	return true, nil
}

func statusO11YDimension(status, path, message string) cluster.StatusO11YDimension {
	return cluster.StatusO11YDimension{Status: status, EvidencePath: path, Message: message}
}

func statusO11YPassedDimension(passed bool, path, failureMessage string) cluster.StatusO11YDimension {
	if passed {
		return statusO11YDimension("passed", path, "")
	}
	return statusO11YDimension("failed", path, failureMessage)
}

func validStatusO11YArtifactProduct(artifact, product string) bool {
	switch artifact {
	case "starter-openapi":
		return product == "starter"
	case "premium-openapi":
		return product == "premium" || product == "essential_v2"
	case "dedicated-openapi":
		return product == "dedicated"
	default:
		return false
	}
}

func statusO11YComplete(layer *cluster.StatusO11YLayer) bool {
	if layer.Platform.Status != "passed" || layer.RoutingMapping["shared"].Status != "passed" ||
		layer.MetricsWriteQuery["shared"].Status != "passed" || layer.PublicWriteNegative.Status != "passed" ||
		layer.Cleanup["shared"].Status != "passed" {
		return false
	}
	for _, product := range statusO11YProducts {
		if layer.RoutingMapping[product].Status != "passed" || layer.ACS[product].Status != "passed" ||
			layer.AgentCR[product].Status != "passed" ||
			layer.AgentWorkload[product].Status != "passed" || layer.MetricsWriteQuery[product].Status != "passed" ||
			layer.NamespaceNegative[product].Status != "passed" || layer.InterruptedRecovery[product].Status != "passed" ||
			layer.Idempotency[product].Status != "passed" ||
			layer.Cleanup[product].Status != "passed" {
			return false
		}
	}
	return true
}
