package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/gorilla/handlers"
	"github.com/jinzhu/gorm"
	"github.com/robfig/cron"

	"gogs.carduccidante.edu.it/karmen/core/config"
	"gogs.carduccidante.edu.it/karmen/core/cron/sync"
	"gogs.carduccidante.edu.it/karmen/core/generator"
	"gogs.carduccidante.edu.it/karmen/core/generator/generators/department"
	"gogs.carduccidante.edu.it/karmen/core/generator/generators/list"
	karmen_handlers "gogs.carduccidante.edu.it/karmen/core/handlers"
	"gogs.carduccidante.edu.it/karmen/core/orm"
)

const (
	MaxNumRetries     = 20
	RetryTimeInterval = 5
)

var (
	db  *gorm.DB
	err error

	models = []interface{}{
		&orm.Teacher{},
		&orm.Department{},
		&orm.Subject{},
		&orm.Class{},
		&orm.Student{},
		&orm.Activity{},
		&orm.Office{},
		&orm.Administrative{},
		&orm.Group{},
		&orm.Document{},
		&orm.Job{},
		&orm.File{},
	}
)

func main() {
	configFile := flag.String("config", "config/config.yaml", "Load the given config file")
	flag.Parse()

	log.Println("Loading config file...")
	err = config.ReadFile(*configFile, config.Config)
	if err != nil {
		panic(err)
	}

	log.Println("Starting karmen and waiting for the DB...")

	count := MaxNumRetries
	wait := true

	for wait && count > 0 {
		db, err = orm.New(fmt.Sprintf("%s?%s", config.Config.Orm.Connection, config.Config.Orm.Options))
		if err != nil {
			count--
			log.Println(err)
			log.Printf("Remaining retries: %d", count)
			time.Sleep(time.Second * RetryTimeInterval)
			continue
		}
		wait = false
	}

	orm.Use(db)

	if config.Config.Orm.AutoMigrate {
		log.Print("Automigrating...")
		orm.AutoMigrate()
	}

	log.Println("Map models <-> handlers")
	if err := orm.MapHandlers(models); err != nil {
		panic(err)
	}

	generator.Generators = make(map[string]generator.Generator)

	log.Println("Initialize ListGenerator")
	generator.Generators["list"] = list.NewListGenerator(config.Config)

	log.Println("Initialize DepartmentGenerator")
	generator.Generators["department"] = department.NewDepartmentGenerator(&generator.Config{ConfigT: *config.Config})

	files, err := filepath.Glob("generator/generators/*")
	if err != nil {
		panic(err)
	}

	log.Println("Found the following generators...", files)
	gTypes := make([]*orm.GeneratorType, 0)
	for _, g := range files {
		gTypes = append(gTypes, &orm.GeneratorType{Name: filepath.Base(g)})
	}
	log.Println("Update generator_types table...")
	for _, gt := range gTypes {
		var gType []orm.GeneratorType
		if err := orm.DB().Where("name = ?", gt.Name).Find(&gType).Error; err != nil {
			panic(err)
		}
		if len(gType) == 0 {
			err := orm.DB().Debug().Create(gt).Error
			if err != nil {
				panic(err)
			}
		}
	}

	if err := orm.DB().Find(&gTypes).Error; err != nil {
		panic(err)
	}
	log.Println("Currently registered generators are:")
	for _, g := range gTypes {
		log.Println(g.Name)
	}

	log.Println("Starting cron jobs...")

	c := cron.New()

	syncJob := sync.NewSyncJob(config.Config)

	if config.Config.Sync.Schedule == "" {
		config.Config.Sync.Schedule = "@every 10m"
	}

	log.Printf("Adding LDAP Sync Job with schedule set at %s", config.Config.Sync.Schedule)
	log.Printf("Sync will run with SAFE mode set to %v", config.Config.Sync.SafeRun)
	log.Printf("Sync will run with SEND_MAIL set to %v", config.Config.Sync.SendMail)
	log.Printf("Sync will run with SCHEDULE set to %v", config.Config.Sync.Schedule)
	c.AddJob(config.Config.Sync.Schedule, syncJob)

	c.Start()

	log.Println("karmen is listening to port 3000...")
	if err := http.ListenAndServe(":3000", handlers.LoggingHandler(os.Stdout, karmen_handlers.Handlers(models))); err != nil {
		panic(err)
	}

}
