package main

import (
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/openaccounting/oa-server/core/api"
	"github.com/openaccounting/oa-server/core/auth"
	"github.com/openaccounting/oa-server/core/model"
	"github.com/openaccounting/oa-server/core/model/types"
	"github.com/openaccounting/oa-server/core/repository"
	"github.com/openaccounting/oa-server/core/util"
	"github.com/openaccounting/oa-server/database"
	"github.com/spf13/viper"
)

func main() {
	// Initialize Viper configuration
	var config types.Config
	
	// Set config file properties
	viper.SetConfigName("config")
	viper.SetConfigType("json")
	viper.AddConfigPath(".")
	viper.AddConfigPath("/etc/openaccounting/")
	viper.AddConfigPath("$HOME/.openaccounting")
	
	// Enable environment variables
	viper.AutomaticEnv()
	viper.SetEnvPrefix("OA") // will look for OA_DATABASE_PASSWORD, etc.
	
	// Set default values
	viper.SetDefault("Address", "localhost")
	viper.SetDefault("Port", 8080)
	viper.SetDefault("DatabaseDriver", "sqlite")
	viper.SetDefault("DatabaseFile", "./openaccounting.db")
	viper.SetDefault("ApiPrefix", "/api/v1")
	
	// Read configuration
	err := viper.ReadInConfig()
	if err != nil {
		log.Printf("Warning: Could not read config file: %v", err)
		log.Println("Using environment variables and defaults")
	}
	
	// Unmarshal config into struct
	err = viper.Unmarshal(&config)
	if err != nil {
		log.Fatal(fmt.Errorf("failed to unmarshal config: %s", err.Error()))
	}

	// Parse database address (assuming format host:port for MySQL)
	host := config.DatabaseAddress
	port := "3306"
	if len(config.DatabaseAddress) > 0 {
		// If there's a colon, split host and port
		if colonIndex := len(config.DatabaseAddress); colonIndex > 0 {
			host = config.DatabaseAddress
		}
	}

	// Default to SQLite if no driver specified
	driver := config.DatabaseDriver
	if driver == "" {
		driver = "sqlite"
	}

	// Initialize GORM database
	dbConfig := &database.Config{
		Driver:   driver,
		Host:     host,
		Port:     port,
		User:     config.User,
		Password: config.Password,
		DBName:   config.Database,
		File:     config.DatabaseFile,
		SSLMode:  "disable", // Adjust as needed
	}

	err = database.Connect(dbConfig)
	if err != nil {
		log.Fatal(fmt.Errorf("failed to connect to database with: %s", err.Error()))
	}

	// Run migrations
	err = database.AutoMigrate()
	if err != nil {
		log.Fatal(fmt.Errorf("failed to run migrations: %s", err.Error()))
	}

	err = database.Migrate()
	if err != nil {
		log.Fatal(fmt.Errorf("failed to run custom migrations: %s", err.Error()))
	}

	bc := &util.StandardBcrypt{}

	// Create GORM repository and models
	gormRepo := repository.NewGormRepository(database.DB)
	gormModel := model.NewGormModel(database.DB, bc, config)
	auth.NewGormAuthService(gormRepo, bc)

	// Set the global model instance
	model.Instance = gormModel

	app, err := api.Init(config.ApiPrefix)
	if err != nil {
		log.Fatal(fmt.Errorf("failed to create api instance with: %s", err.Error()))
	}

	if config.CertFile == "" || config.KeyFile == "" {
		err = http.ListenAndServe(config.Address+":"+strconv.Itoa(config.Port), app.MakeHandler())
	} else {
		err = http.ListenAndServeTLS(config.Address+":"+strconv.Itoa(config.Port), config.CertFile, config.KeyFile, app.MakeHandler())
	}
	log.Fatal(fmt.Errorf("failed to start server with: %s", err.Error()))
}
