package main

import (
	"context"
	"database/sql"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"

	"screenmark/screenmark/.gen/haystack/haystack/model"
	. "screenmark/screenmark/.gen/haystack/haystack/table"

	"github.com/go-chi/chi/v5"
	. "github.com/go-jet/jet/v2/postgres"
	"github.com/robert-nix/ansihtml"

	"github.com/charmbracelet/log"
	"github.com/google/uuid"
	"github.com/muesli/termenv"
)

type DatabaseWriter struct {
	dbPool  *sql.DB
	imageId uuid.UUID
}

func (w *DatabaseWriter) Write(p []byte) (n int, err error) {
	if len(p) == 0 {
		return 0, nil
	}

	insertLogStmt := Logs.
		INSERT(Logs.Log, Logs.ImageID).
		VALUES(string(p), w.imageId)

	_, err = insertLogStmt.Exec(w.dbPool)

	if err != nil {
		return 0, err
	} else {
		return len(p), nil
	}
}

func (w *DatabaseWriter) GetImageLogs(ctx context.Context, imageId uuid.UUID) ([]string, error) {
	getImageLogsStmt := Logs.
		SELECT(Logs.Log).
		WHERE(Logs.ImageID.EQ(UUID(imageId)))

	logs := []model.Logs{}
	err := getImageLogsStmt.QueryContext(ctx, w.dbPool, &logs)

	if err != nil {
		return []string{}, err
	}

	stringLogs := make([]string, len(logs))
	for i, log := range logs {
		stringLogs[i] = log.Log
	}

	return stringLogs, nil
}

func createLogHandler(logWriter *DatabaseWriter) func(r chi.Router) {
	return func(r chi.Router) {
		r.Get("/{imageId}", func(w http.ResponseWriter, r *http.Request) {
			stringImageId := r.PathValue("imageId")
			imageId, err := uuid.Parse(stringImageId)
			if err != nil {
				w.WriteHeader(http.StatusBadGateway)
				return
			}

			logs, err := logWriter.GetImageLogs(r.Context(), imageId)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				return
			}

			html := ""

			imageTag := fmt.Sprintf(`<image src="https://haystack.johncosta.tech/image/%s">`, stringImageId)

			for _, log := range logs {
				html += fmt.Sprintf("<div>%s</div>", string(ansihtml.ConvertToHTML([]byte(log)))+"\n")
			}

			css := `
<style>
  body {
    background-color: #1e1e1e;
    color: #f0f0f0;
    font-family: sans-serif;
    line-height: 1.6;
    margin: 0;
    padding: 20px;
  }

  /* Basic styling for code blocks often used for logs */
  pre {
    background-color: #2a2a2a;
    padding: 1em;
    border-radius: 4px;
    overflow-x: auto;
    border: 1px solid #444;
  }

  code {
    font-family: monospace;
  }
</style>
			`

			fullHtml := fmt.Sprintf("<html><head><title>Logs</title>%s</head><body>%s%s</body></html>", css, imageTag, html)

			w.Header().Add("Content-Type", "text/html")
			w.Write([]byte(fullHtml))
			w.WriteHeader(http.StatusOK)
		})
	}
}

func newDatabaseWriter(dbPool *sql.DB, imageId uuid.UUID) *DatabaseWriter {
	return &DatabaseWriter{
		dbPool:  dbPool,
		imageId: imageId,
	}
}

func createDbStdoutWriter(dbPool *sql.DB, imageId uuid.UUID) io.Writer {
	return io.MultiWriter(os.Stdout, newDatabaseWriter(dbPool, imageId))
}

func createLogger(prefix string, writer io.Writer) *log.Logger {
	logger := log.NewWithOptions(writer, log.Options{
		ReportTimestamp: true,
		TimeFormat:      time.Kitchen,
		Prefix:          prefix,
		Formatter:       log.TextFormatter,
	})

	logger.SetColorProfile(termenv.TrueColor)
	logger.SetLevel(log.DebugLevel)

	return logger
}
