package main

import (
	"context"
	"database/sql"
	"fmt"
	"github.com/google/uuid"
	httpSwagger "github.com/swaggo/http-swagger"
	_ "go-nkode/docs"
	"go-nkode/internal/api"
	"go-nkode/internal/email"
	"go-nkode/internal/models"
	"go-nkode/internal/repository"
	sqliteQueue "go-nkode/internal/sqlc"
	"log"
	"net/http"
	"os"
)

const (
	emailQueueBufferSize = 100
	maxEmailsPerSecond   = 13 // SES allows 14, but I don't want to push it
)

// @title           NKode API
// @version         1.0
// @description     This is the NKode API server.
// @termsOfService  http://nkode.example.com/terms/

// @contact.name   API Support
// @contact.url    http://nkode.example.com/support
// @contact.email  support@nkode.example.com

// @license.name  MIT
// @license.url   https://opensource.org/licenses/MIT

// @host      localhost:8080
// @BasePath  /

// @securityDefinitions.apiKey  ApiKeyAuth
// @in                          header
// @name                        Authorization
func main() {
	dbPath := os.Getenv("SQLITE_DB")
	if dbPath == "" {
		log.Fatal("SQLITE_DB=/path/to/nkode.db not set")
	}

	sqliteDb, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		log.Fatalf("failed to open database: %v", err)
	}

	if err := sqliteDb.Ping(); err != nil {
		log.Fatalf("failed to connect to database: %v", err)
	}

	ctx := context.Background()
	queue, err := sqliteQueue.NewQueue(ctx, sqliteDb)
	if err != nil {
		log.Fatal(err)
	}
	queue.Start()

	defer func(queue *sqliteQueue.Queue) {
		if err := queue.Stop(); err != nil {
			log.Fatal(err)
		}
	}(queue)
	sesClient := email.NewSESClient()
	emailQueue := email.NewEmailQueue(emailQueueBufferSize, maxEmailsPerSecond, &sesClient)
	emailQueue.Start()
	defer emailQueue.Stop()
	sqlitedb := repository.NewSqliteRepository(ctx, queue)
	nkodeApi := api.NewNKodeAPI(&sqlitedb, emailQueue)
	AddDefaultCustomer(nkodeApi)
	handler := api.NKodeHandler{Api: nkodeApi}
	mux := http.NewServeMux()
	mux.Handle(api.CreateNewCustomer, &handler)
	mux.Handle(api.GenerateSignupResetInterface, &handler)
	mux.Handle(api.SetNKode, &handler)
	mux.Handle(api.ConfirmNKode, &handler)
	mux.Handle(api.GetLoginInterface, &handler)
	mux.Handle(api.Login, &handler)
	mux.Handle(api.RenewAttributes, &handler)
	mux.Handle(api.RandomSvgInterface, &handler)
	mux.Handle(api.RefreshToken, &handler)
	mux.Handle(api.ResetNKode, &handler)
	// Serve Swagger UI
	mux.Handle("/swagger/", httpSwagger.WrapHandler)
	fmt.Println("Running on localhost:8090...")
	log.Fatal(http.ListenAndServe(":8090", corsMiddleware(mux)))
}

func corsMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Set the CORS headers
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

		// Handle preflight requests
		if r.Method == http.MethodOptions {
			w.WriteHeader(http.StatusNoContent)
			return
		}

		// Call the next handler
		next.ServeHTTP(w, r)
	})
}

func AddDefaultCustomer(nkodeApi api.NKodeAPI) {
	newId, err := uuid.Parse("ed9ed6e0-082c-4b57-8d8c-f00ed6493457")
	if err != nil {
		log.Fatal(err)
	}
	customerId := models.CustomerID(newId)
	nkodePolicy := models.NewDefaultNKodePolicy()
	_, err = nkodeApi.CreateNewCustomer(nkodePolicy, &customerId)
	if err != nil {
		log.Println(err)
	} else {
		log.Println("created new customer: ", newId)
	}
}
