package main

import (
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"momswap/backend/internal/app"
	httpapi "momswap/backend/internal/http"
	"momswap/backend/internal/storage"
	"momswap/backend/internal/store"
)

func main() {
	addr := getEnv("ADDR", ":8122")
	adminPublicKey := os.Getenv("ADMIN_PUBLIC_KEY")
	servicePublicKey := getEnv("SERVICE_PUBLIC_KEY", adminPublicKey)

	if adminPublicKey == "" {
		adminPublicKey = readKeyFile(getEnv("ADMIN_PUBLIC_KEY_FILE", "etc/server-service.pub"))
	}
	if servicePublicKey == "" {
		servicePublicKey = readKeyFile(getEnv("SERVICE_PUBLIC_KEY_FILE", "etc/server-service.pub"))
	}
	if servicePublicKey == "" {
		servicePublicKey = adminPublicKey
	}

	var st store.Store
	if databaseURL := os.Getenv("DATABASE_URL"); databaseURL != "" {
		if err := store.Migrate(databaseURL); err != nil {
			log.Fatalf("migrate: %v", err)
		}
		pg, err := store.NewPostgresStore(databaseURL)
		if err != nil {
			log.Fatalf("postgres: %v", err)
		}
		defer pg.Close()
		st = pg
	} else {
		st = store.NewMemoryStore()
	}

	service := app.NewService(st, app.Config{
		ChallengeTTL: 5 * time.Minute,
		SessionTTL:   24 * time.Hour,
	}, servicePublicKey)
	service.BootstrapAdmin(adminPublicKey)
	if signer, err := newAssetSignerFromEnv(); err != nil {
		log.Printf("asset storage disabled: %v", err)
	} else if signer != nil {
		service.ConfigureAssetStorage(signer)
	}

	api := httpapi.NewAPI(service)
	h := api.Routes()
	if logDir := getEnv("LOG_DIR", "var/logs"); logDir != "" {
		if wrapped, err := httpapi.WithRequestLogging(logDir, h); err != nil {
			log.Printf("request logging disabled: %v", err)
		} else {
			h = wrapped
		}
	}
	log.Printf("listening on %s", addr)
	if err := http.ListenAndServe(addr, h); err != nil {
		log.Fatalf("listen: %v", err)
	}
}

func newAssetSignerFromEnv() (app.AssetURLSigner, error) {
	endpoint := os.Getenv("S3_ENDPOINT")
	bucket := os.Getenv("S3_BUCKET")
	if endpoint == "" || bucket == "" {
		return nil, nil
	}
	useTLS, err := strconv.ParseBool(getEnv("S3_USE_TLS", "false"))
	if err != nil {
		return nil, err
	}
	usePathStyle, err := strconv.ParseBool(getEnv("S3_USE_PATH_STYLE", "true"))
	if err != nil {
		return nil, err
	}
	signer, err := storage.NewS3Signer(storage.S3Config{
		Endpoint:  endpoint,
		Region:    getEnv("S3_REGION", "us-east-1"),
		Bucket:    bucket,
		AccessKey: getEnv("S3_ACCESS_KEY", ""),
		SecretKey: getEnv("S3_SECRET_KEY", ""),
		UseTLS:    useTLS,
		PathStyle: usePathStyle,
	})
	if err != nil {
		return nil, err
	}
	return signer, nil
}

func getEnv(key, fallback string) string {
	v := os.Getenv(key)
	if v == "" {
		return fallback
	}
	return v
}

func readKeyFile(path string) string {
	b, err := os.ReadFile(path)
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(b))
}
