package handlers

import (
	"net/http"
	"time"

	"xorm.io/xorm"

	"github.com/forgeo/forgebucket/internal/events"
	"github.com/forgeo/forgebucket/internal/models"
	"github.com/forgeo/forgebucket/internal/observability"
)

// ── /health ───────────────────────────────────────────────────────────────────

type HealthHandler struct {
	db  *xorm.Engine
	bus events.EventBus
}

func NewHealthHandler(db *xorm.Engine, bus events.EventBus) *HealthHandler {
	return &HealthHandler{db: db, bus: bus}
}

func (h *HealthHandler) Health(w http.ResponseWriter, r *http.Request) {
	status := observability.Check(h.db, h.bus)
	if status.Status != "healthy" {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusServiceUnavailable)
		jsonOK(w, status)
		return
	}
	jsonOK(w, status)
}

// ── /api/v1/repos/{owner}/{repo}/health ──────────────────────────────────────

type RepoHealthHandler struct{ db *xorm.Engine }

func NewRepoHealthHandler(db *xorm.Engine) *RepoHealthHandler {
	return &RepoHealthHandler{db: db}
}

type latestDeployment struct {
	EnvName    string     `json:"envName"`
	Status     string     `json:"status"`
	SHA        string     `json:"sha"`
	FinishedAt *time.Time `json:"finishedAt"`
}

type repoHealthResponse struct {
	CIPassRate7d       float64            `json:"ciPassRate7d"`
	TotalRuns7d        int                `json:"totalRuns7d"`
	LatestRun          *models.PipelineRun `json:"latestRun"`
	LatestDeployments  []latestDeployment  `json:"latestDeployments"`
	OpenDriftCount     int                 `json:"openDriftCount"`
	OpenPRCount        int                 `json:"openPRCount"`
}

// Get returns an operational health summary for a repository.
// This feeds the repo page header: CI pass rate, latest deploy per env, drift count.
func (h *RepoHealthHandler) Get(w http.ResponseWriter, r *http.Request) {
	repoID, ok := resolveRepoID(h.db, w, r)
	if !ok {
		return
	}

	since7d := time.Now().UTC().Add(-7 * 24 * time.Hour)

	// CI pass rate over last 7 days.
	var runs []models.PipelineRun
	h.db.Where("repo_id = ? AND created_at >= ?", repoID, since7d).Find(&runs)
	total := len(runs)
	succeeded := 0
	for _, run := range runs {
		if run.Status == "succeeded" {
			succeeded++
		}
	}
	var passRate float64
	if total > 0 {
		passRate = float64(succeeded) / float64(total)
	}

	// Latest run overall.
	var latestRun models.PipelineRun
	var hasLatest bool
	hasLatest, _ = h.db.Where("repo_id = ?", repoID).Desc("id").Limit(1).Get(&latestRun)

	// Latest deployment per environment.
	var envs []models.Environment
	h.db.Where("repo_id = ?", repoID).Find(&envs)
	deploys := make([]latestDeployment, 0, len(envs))
	for _, env := range envs {
		var d models.Deployment
		if found, _ := h.db.Where("env_id = ?", env.ID).Desc("id").Limit(1).Get(&d); found {
			deploys = append(deploys, latestDeployment{
				EnvName:    env.Name,
				Status:     string(d.Status),
				SHA:        d.SHA,
				FinishedAt: d.FinishedAt,
			})
		}
	}

	// Open drift count (GitOpsConfigs where sync_status = 'drifted').
	driftCount, _ := h.db.Where("repo_id = ? AND sync_status = 'drifted'", repoID).
		Count(&models.GitOpsConfig{})

	// Open PR count.
	prCount, _ := h.db.Where("repo_id = ? AND status = 'open'", repoID).
		Count(&models.PullRequest{})

	resp := repoHealthResponse{
		CIPassRate7d:      passRate,
		TotalRuns7d:       total,
		LatestDeployments: deploys,
		OpenDriftCount:    int(driftCount),
		OpenPRCount:       int(prCount),
	}
	if hasLatest {
		resp.LatestRun = &latestRun
	}

	jsonOK(w, resp)
}
