package main

import (
	"context"
	"database/sql"
	"html/template"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"
	_ "github.com/jackc/pgx/v5/stdlib"
	"github.com/pressly/goose/v3"
	"github.com/sirupsen/logrus"
)

// TemplateWrapper adapts html/template.Template to TemplateExecutor
// (implements Execute(http.ResponseWriter, interface{}) error)
type TemplateWrapper struct {
	Tmpl *template.Template
}

func (tw *TemplateWrapper) Execute(wr http.ResponseWriter, data interface{}) error {
	return tw.Tmpl.Execute(wr, data)
}

func main() {
	logrus.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
	logrus.SetLevel(logrus.InfoLevel)

	if err := loadConfig("config.yaml"); err != nil {
		logrus.Fatalf("Failed to load config.yaml: %v", err)
	}
	logrus.Infof("Loaded config: %+v", appConfig)
	visitDB := NewVisitDB()

	if err := loadUITemplate("ui.html"); err != nil {
		logrus.Fatalf("Failed to load ui.html: %v", err)
	}
	if err := loadDBEditTemplate("ui_dbedit.html"); err != nil {
		logrus.Fatalf("Failed to load ui_dbedit.html: %v", err)
	}
	if err := loadAdminChatsTemplate("ui_admin_chats.html"); err != nil {
		logrus.Fatalf("Failed to load ui_admin_chats.html: %v", err)
	}

	// Initialize PostgreSQL repository first
	dsn := buildDefaultDSN()
	logrus.Info("Connecting to PostgreSQL with DSN: ", dsn)

	// Run goose migrations using database/sql with pgx driver before initializing repository
	if dsn != "" {
		sqlDB, err := sql.Open("pgx", dsn)
		if err != nil {
			logrus.Fatalf("Failed to open database for migration: %v", err)
		}
		defer sqlDB.Close()
		goose.SetDialect("postgres")
		if err := goose.Up(sqlDB, "migrations"); err != nil {
			logrus.Fatalf("Goose migration failed: %v", err)
		}
		logrus.Info("Database migrations applied successfully (goose)")
	}

	repo, err := NewPGChatRepository(context.Background(), dsn)
	if err != nil {
		logrus.WithError(err).Warn("PostgreSQL repository disabled (connection failed)")
	} else if repo == nil {
		logrus.Info("PostgreSQL repository not configured (no DSN)")
	}
	// defer repo.Close() // optionally enable

	// Initialize LLM client
	llmClient := NewLLMClient(
		os.Getenv("OPENAI_API_KEY"),
		os.Getenv("OPENAI_BASE_URL"),
		os.Getenv("OPENAI_MODEL"),
		repo,
	)
	var llm LLMClientAPI = llmClient

	// Wrap templates for controller
	uiTmpl := &TemplateWrapper{Tmpl: uiTemplate}
	uiDBEditTmpl := &TemplateWrapper{Tmpl: uiDBEditTemplate}
	uiAdminChatsTmpl := &TemplateWrapper{Tmpl: uiAdminChatsTemplate}

	// Create controller
	ctrl := NewController(
		repo,
		llm,
		&visitDB,
		uiTmpl,
		uiDBEditTmpl,
		uiAdminChatsTmpl,
	)

	r := gin.Default()
	// Routes
	r.GET("/", ctrl.RootUI)
	r.GET("/health", ctrl.Health)
	r.POST("/chat", ctrl.HandleChat)

	r.GET("/admin", ctrl.AdminUI)
	r.GET("/db.yaml", ctrl.DownloadDB)

	// KnowledgeModel endpoints (replaces snapshot)
	r.POST("/admin/chats/snapshot", ctrl.SaveKnowledgeModel)
	r.GET("/admin/chats/snapshots", ctrl.ListKnowledgeModels)
	r.GET("/admin/chats/snapshot/:id", ctrl.GetKnowledgeModel)

	// Chat interactions and events
	r.GET("/admin/chats", ctrl.ListChatInteractions)
	r.GET("/admin/chats/events", ctrl.ListLLMEvents)
	r.GET("/admin/chats/ui", ctrl.AdminChatsUI)

	r.Run(":8080")
}
