package main

import (
	"flag"

	"git.gocasts.ir/ebhomengo/niki/adapter/redis"
	"git.gocasts.ir/ebhomengo/niki/config"
	httpserver "git.gocasts.ir/ebhomengo/niki/delivery/http_server"
	"git.gocasts.ir/ebhomengo/niki/internal/initial"
	"git.gocasts.ir/ebhomengo/niki/repository/migrator"
	"git.gocasts.ir/ebhomengo/niki/repository/mysql"
	_ "github.com/go-sql-driver/mysql"
)

type Dependencies struct {
	initial.Auth
	initial.Databases
	initial.Validators
	initial.Services
	initial.AdminAuthorization
}

func parseFlags() bool {
	migrateFlag := flag.Bool("migrate", false, "perform database migration")
	flag.Parse()
	return *migrateFlag
}

// @securityDefinitions.apikey AuthBearerBenefactor
// @in header
// @name Authorization
// @description Type the word 'Bearer' followed by a space and Benefactor JWT token
// @securityDefinitions.apikey  AuthBearerAdmin
// @in header
// @name Authorization
// @description Type the word 'Bearer' followed by a space and Admin JWT token
func main() {
	migrate := parseFlags()

	cfg := config.C()
	db := initDatabase(cfg, migrate)
	redisAdapter := initRedis(cfg)

	dependencies := initDependencies(cfg, redisAdapter, db)

	initAndRunServer(cfg, dependencies)
}

func initDependencies(cfg config.Config, redisAdapter redis.Adapter, db *mysql.DB) *Dependencies {
	return &Dependencies{
		initial.Auth{
			BenefactorAuthSvc: initial.InitBenefactorAuthService(cfg),
			AdminAuthSvc:      initial.InitAdminAuthService(cfg),
		},
		initial.Databases{
			BenefactorAddressDB:    initial.InitBenefactorAddressDB(db),
			BenefactorKindBoxReqDB: initial.InitBenefactorKindBoxReqDB(db),
			KindBoxRepo:            initial.InitKindBoxRepo(db),
			AdminMysql:             initial.InitAdminMysql(db),
		},
		initial.Validators{
			BenefactorVld:           initial.InitBenefactorValidator(),
			BenefactorKindBoxReqVld: initial.InitBenefactorKindBoxReqValidator(cfg, redisAdapter, db),
			BenefactorAddressVld:    initial.InitBenefactorAddressValidator(cfg, redisAdapter, db),
			AdminKindBoxReqVld:      initial.InitAdminKindBoxReqValidator(db, cfg),
			AdminVld:                initial.InitAdminValidator(db),
		},
		initial.Services{
			BenefactorSvc:           initial.InitBenefactorService(cfg, redisAdapter, db),
			BenefactorKindBoxReqSvc: initial.InitBenefactorKindBoxReqService(db),
			BenefactorAddressSvc:    initial.InitBenefactorAddressService(db),
			AdminKindBoxSvc:         initial.InitAdminKindBoxService(db),
			AdminKindBoxReqSvc:      initial.InitAdminKindBoxReqService(db),
			AdminSvc:                initial.InitAdminService(cfg, db),
			AdminReferTimeSvc:       initial.InitAdminReferTimeService(db),
		},
		initial.AdminAuthorization{
			AdminAuthorizationSvc: initial.InitAdminAuthorizationService(db),
		},
	}
}

func initAndRunServer(cfg config.Config, dependencies *Dependencies) {
	server := httpserver.New(cfg,
		dependencies.BenefactorSvc, dependencies.BenefactorVld, dependencies.BenefactorAuthSvc,
		dependencies.BenefactorKindBoxReqSvc, dependencies.BenefactorKindBoxReqVld,
		dependencies.BenefactorAddressSvc, dependencies.BenefactorAddressVld,
		dependencies.AdminSvc, dependencies.AdminVld, dependencies.AdminAuthSvc,
		dependencies.AdminKindBoxReqSvc, dependencies.AdminKindBoxReqVld, dependencies.AdminAuthorizationSvc)

	server.Serve()
}

func initDatabase(cfg config.Config, migrate bool) *mysql.DB {
	if migrate {
		migrateDatabase(cfg)
	}

	return initial.InitMysql(cfg)
}

func initRedis(cfg config.Config) redis.Adapter {
	return redis.New(cfg.Redis)
}

func migrateDatabase(cfg config.Config) {
	migratorDB := migrator.New(cfg.Mysql)
	migratorDB.Up()
}