package web

import (
	"fmt"
	"net/http"

	"gitea.dooplex.hu/admin/felhom-controller/internal/scheduler"
	"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
	"gitea.dooplex.hu/admin/felhom-controller/internal/system"
)

func (s *Server) baseData(page, title string) map[string]interface{} {
	return map[string]interface{}{
		"Page":         page,
		"Title":        title,
		"CustomerName": s.cfg.Customer.Name,
		"Domain":       s.cfg.Customer.Domain,
		"Version":      s.version,
	}
}

func (s *Server) dashboardHandler(w http.ResponseWriter, _ *http.Request) {
	stackList := s.stackMgr.GetStacks()

	running, stopped := 0, 0
	for _, st := range stackList {
		switch st.State {
		case stacks.StateRunning:
			running++
		case stacks.StateStopped, stacks.StateExited:
			stopped++
		case stacks.StateStarting, stacks.StateUnhealthy, stacks.StateRestarting:
			// Count starting/unhealthy/restarting as "running" for the dashboard stat
			// (they have containers, they're just not fully healthy yet)
			running++
		}
	}

	// Filter to deployed + protected stacks only for dashboard display
	var deployedStacks []stacks.Stack
	for _, st := range stackList {
		if st.Deployed || st.Protected {
			deployedStacks = append(deployedStacks, st)
		}
	}

	sysInfo := system.GetInfo(s.cfg.Paths.HDDPath, s.cpuCollector)

	data := s.baseData("dashboard", "Vezérlőpult")
	data["Stacks"] = deployedStacks
	data["RunningCount"] = running
	data["StoppedCount"] = stopped
	data["TotalCount"] = len(stackList)
	data["SystemInfo"] = sysInfo

	// Backup status
	data["BackupEnabled"] = s.cfg.Backup.Enabled
	if s.backupMgr != nil {
		nextDBDump := scheduler.NextDailyRun(s.cfg.Backup.DBDumpSchedule)
		nextBackup := scheduler.NextDailyRun(s.cfg.Backup.ResticSchedule)
		fullStatus := s.backupMgr.GetFullStatus(nextDBDump, nextBackup)
		data["DBDumpStatus"] = fullStatus.LastDBDump
		data["BackupStatus"] = fullStatus.LastBackup
		data["BackupRunning"] = fullStatus.Running
		data["BackupMaxAgeHours"] = s.cfg.Monitoring.Thresholds.BackupMaxAgeHours
	}

	s.render(w, "dashboard", data)
}

func (s *Server) stacksHandler(w http.ResponseWriter, _ *http.Request) {
	data := s.baseData("stacks", "Alkalmazások")
	data["Stacks"] = s.stackMgr.GetStacks()
	s.render(w, "stacks", data)
}

func (s *Server) logsHandler(w http.ResponseWriter, r *http.Request, name string) {
	stack, ok := s.stackMgr.GetStack(name)
	if !ok {
		http.NotFound(w, r)
		return
	}

	logs, err := s.stackMgr.GetLogs(name, 200)
	if err != nil {
		logs = fmt.Sprintf("Hiba a naplók lekérésekor: %v", err)
	}

	// Raw mode: return plain text for AJAX polling
	if r.URL.Query().Get("raw") == "1" {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		fmt.Fprint(w, logs)
		return
	}

	data := s.baseData("logs", stack.Meta.DisplayName+" — Naplók")
	data["Stack"] = stack
	data["Logs"] = logs
	s.render(w, "logs", data)
}

func (s *Server) deployHandler(w http.ResponseWriter, _ *http.Request, name string) {
	meta, appCfg, err := s.stackMgr.GetDeployFields(name)
	if err != nil {
		http.NotFound(w, nil)
		return
	}

	stack, _ := s.stackMgr.GetStack(name)
	alreadyDeployed := appCfg != nil && appCfg.Deployed

	data := s.baseData("deploy", meta.DisplayName+" — Telepítés")
	data["Stack"] = stack
	data["Meta"] = meta
	data["AppConfig"] = appCfg
	data["AlreadyDeployed"] = alreadyDeployed
	data["LogoURL"] = s.cfg.AppLogoURL(meta.Slug)
	data["LogoPNGURL"] = s.cfg.AppLogoPNGURL(meta.Slug)
	data["AppPageURL"] = s.cfg.AppPageURL(meta.Slug)
	data["UserFields"] = meta.UserFacingFields()
	data["AutoFields"] = meta.AutoGeneratedFields()

	// Memory info for deploy page (only for non-deployed apps)
	if !alreadyDeployed {
		memInfo := map[string]interface{}{"Available": false}
		totalMB, memErr := system.GetTotalMemoryMB()
		if memErr == nil {
			reservedMB := s.cfg.System.ReservedMemoryMB
			usableMB := totalMB - reservedMB
			committedReqMB, committedLimitMB := s.stackMgr.CommittedMemory()
			newReqMB := stacks.ParseMemoryMB(meta.Resources.MemRequest)
			newLimitMB := stacks.ParseMemoryMB(meta.Resources.MemLimit)
			afterReqMB := committedReqMB + newReqMB
			afterLimitMB := committedLimitMB + newLimitMB
			percent := 0
			if usableMB > 0 {
				percent = afterReqMB * 100 / usableMB
			}

			committedPercent := 0
			if usableMB > 0 {
				committedPercent = committedReqMB * 100 / usableMB
			}

			memInfo["Available"] = true
			memInfo["TotalMB"] = totalMB
			memInfo["ReservedMB"] = reservedMB
			memInfo["UsableMB"] = usableMB
			memInfo["CommittedMB"] = committedReqMB
			memInfo["NewRequestMB"] = newReqMB
			memInfo["AfterMB"] = afterReqMB
			memInfo["Percent"] = percent
			memInfo["CommittedPercent"] = committedPercent
			memInfo["Blocked"] = newReqMB > 0 && afterReqMB > usableMB
			memInfo["OvercommitWarn"] = newLimitMB > 0 && afterLimitMB > totalMB
		}
		data["MemoryInfo"] = memInfo
	}

	s.render(w, "deploy", data)
}

func (s *Server) appDetailHandler(w http.ResponseWriter, _ *http.Request, slug string) {
	var found *stacks.Stack
	for _, stack := range s.stackMgr.GetStacks() {
		if stack.Meta.Slug == slug {
			found = &stack
			break
		}
	}
	if found == nil {
		http.NotFound(w, nil)
		return
	}

	// Load current optional config values from app.yaml
	currentValues := make(map[string]string)
	if appCfg := s.stackMgr.LoadAppConfigByName(found.Name); appCfg != nil {
		for k, v := range appCfg.Env {
			currentValues[k] = v
		}
	}

	data := s.baseData("stacks", found.Meta.DisplayName)
	data["Stack"] = found
	data["Meta"] = found.Meta
	data["AppInfo"] = found.Meta.AppInfo
	data["OptionalConfig"] = found.Meta.OptionalConfig
	data["CurrentValues"] = currentValues
	data["HasAppInfo"] = found.Meta.HasAppInfo()
	data["HasOptionalConfig"] = found.Meta.HasOptionalConfig()

	s.render(w, "app_info", data)
}

func (s *Server) monitoringHandler(w http.ResponseWriter, _ *http.Request) {
	data := s.baseData("monitoring", "Rendszermonitor")
	data["SystemInfo"] = system.GetInfo(s.cfg.Paths.HDDPath, s.cpuCollector)
	s.render(w, "monitoring", data)
}

func (s *Server) backupsHandler(w http.ResponseWriter, _ *http.Request) {
	data := s.baseData("backups", "Biztonsági mentés")

	if s.backupMgr != nil {
		nextDBDump := scheduler.NextDailyRun(s.cfg.Backup.DBDumpSchedule)
		nextBackup := scheduler.NextDailyRun(s.cfg.Backup.ResticSchedule)
		fullStatus := s.backupMgr.GetFullStatus(nextDBDump, nextBackup)
		data["Backup"] = fullStatus
	} else {
		data["Backup"] = nil
	}

	s.render(w, "backups", data)
}
