package main

import (
	"encoding/hex"
	"fmt"
	"io/fs"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/mish/dealspace/api"
	"github.com/mish/dealspace/lib"
)

func main() {
	cfg, err := loadConfig()
	if err != nil {
		log.Fatalf("config: %v", err)
	}

	// Resolve migration path relative to binary or working directory
	migrationPath := findMigration()

	db, err := lib.OpenDB(cfg.DBPath, migrationPath)
	if err != nil {
		log.Fatalf("database: %v", err)
	}
	defer db.Close()

	store, err := lib.NewLocalStore(cfg.StorePath)
	if err != nil {
		log.Fatalf("object store: %v", err)
	}

	// Always seed super admin accounts on startup
	seedSuperAdmins(db)

	// Seed OAuth client for Claude
	api.SeedOAuthClient(db)

	// Seed demo data if SEED_DEMO=true
	if os.Getenv("SEED_DEMO") == "true" {
		seedDemoData(db, cfg)
	}

	// Website FS: serve from disk (dev: website/, prod: /opt/dealspace/website/)
	var websiteFS fs.FS
	for _, dir := range []string{"website", "/opt/dealspace/website"} {
		if info, err := os.Stat(dir); err == nil && info.IsDir() {
			websiteFS = os.DirFS(dir)
			break
		}
	}

	// MCP server for Claude integration
	mcpServer := api.NewMCPServer(db, cfg)

	router := api.NewRouter(db, cfg, store, websiteFS, nil, mcpServer)

	addr := ":" + cfg.Port
	log.Printf("dealspace starting on %s (env=%s)", addr, cfg.Env)
	if err := http.ListenAndServe(addr, router); err != nil {
		log.Fatalf("server: %v", err)
	}
}

func loadConfig() (*lib.Config, error) {
	// Load .env if it exists
	loadDotEnv()

	masterKeyHex := os.Getenv("MASTER_KEY")
	if masterKeyHex == "" {
		return nil, fmt.Errorf("MASTER_KEY environment variable required")
	}
	masterKey, err := hex.DecodeString(masterKeyHex)
	if err != nil {
		return nil, fmt.Errorf("MASTER_KEY must be hex: %w", err)
	}
	if len(masterKey) != 32 {
		return nil, fmt.Errorf("MASTER_KEY must be 32 bytes (64 hex chars)")
	}

	dbPath := os.Getenv("DB_PATH")
	if dbPath == "" {
		dbPath = "dealspace.db"
	}

	storePath := os.Getenv("STORE_PATH")
	if storePath == "" {
		storePath = "store"
	}

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	env := os.Getenv("ENV")
	if env == "" {
		env = "development"
	}

	// JWT secret derived from master key
	jwtSecret, err := lib.DeriveProjectKey(masterKey, "jwt-signing")
	if err != nil {
		return nil, fmt.Errorf("derive jwt secret: %w", err)
	}

	// Backdoor OTP code for dev/testing
	backdoorCode := os.Getenv("BACKDOOR_CODE")

	cfg := &lib.Config{
		MasterKey:     masterKey,
		DBPath:        dbPath,
		StorePath:     storePath,
		Port:          port,
		Env:           env,
		JWTSecret:     jwtSecret,
		BackdoorCode:  backdoorCode,
		OpenRouterKey: os.Getenv("OPENROUTER_API_KEY"),
	}

	// Initialize mailer
	cfg.Mailer = lib.NewMailer(cfg)
	if cfg.Mailer.Enabled() {
		emailDir := findEmailTemplates()
		if emailDir != "" {
			if err := cfg.Mailer.LoadTemplates(emailDir); err != nil {
				return nil, fmt.Errorf("load email templates: %w", err)
			}
		}
	}

	return cfg, nil
}

func loadDotEnv() {
	data, err := os.ReadFile(".env")
	if err != nil {
		return
	}
	for _, line := range splitLines(string(data)) {
		if line == "" || line[0] == '#' {
			continue
		}
		for i := 0; i < len(line); i++ {
			if line[i] == '=' {
				key := line[:i]
				val := line[i+1:]
				if os.Getenv(key) == "" {
					os.Setenv(key, val)
				}
				break
			}
		}
	}
}

func splitLines(s string) []string {
	var lines []string
	start := 0
	for i := 0; i < len(s); i++ {
		if s[i] == '\n' {
			line := s[start:i]
			if len(line) > 0 && line[len(line)-1] == '\r' {
				line = line[:len(line)-1]
			}
			lines = append(lines, line)
			start = i + 1
		}
	}
	if start < len(s) {
		lines = append(lines, s[start:])
	}
	return lines
}

func findEmailTemplates() string {
	candidates := []string{
		"portal/emails",
		filepath.Join(filepath.Dir(os.Args[0]), "portal/emails"),
		"/opt/dealspace/portal/emails",
	}
	for _, p := range candidates {
		if info, err := os.Stat(p); err == nil && info.IsDir() {
			return p
		}
	}
	return ""
}

func findMigration() string {
	candidates := []string{
		"migrations",
		filepath.Join(filepath.Dir(os.Args[0]), "migrations"),
		"/opt/dealspace/migrations",
	}
	for _, p := range candidates {
		if info, err := os.Stat(p); err == nil && info.IsDir() {
			return p
		}
	}
	return "" // no migration found, skip
}
