package main

import (
	"database/sql"
	"embed"
	"github.com/flamego/captcha"
	"github.com/flamego/cors"
	"github.com/flamego/flamego"
	"github.com/flamego/session"
	sredis "github.com/flamego/session/redis"
	"github.com/flamego/template"
	"github.com/go-redis/redis/v8"
	"github.com/golang-migrate/migrate/v4"
	"github.com/golang-migrate/migrate/v4/database/mysql"
	"github.com/golang-migrate/migrate/v4/source/iofs"
	"github.com/jmoiron/sqlx"
	"github.com/joho/godotenv"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"kuvia/pkg/globaleuserdata"
	"net/http"
	"os"
)

//go:embed public
var public embed.FS

//go:embed templates
var templates embed.FS

//go:embed database/migrations/*.sql
var database embed.FS

var sqlConnection *sqlx.DB

var s3 *minio.Client

func migrateDB()  {
	log.Info().Msg("Run Migration if exists")
	db, err := sql.Open("mysql", os.Getenv("DB_MIGRATION"))
	if err != nil {
		panic(err)
	}
	driver, err := mysql.WithInstance(db, &mysql.Config{})
	if err != nil {
		panic(err)
	}
	d, err := iofs.New(database, "database/migrations")
	if err != nil {
		panic(err)
	}

	m, err := migrate.NewWithInstance("iofs", d, "mysql", driver)
	if err != nil {
		panic(err)
	}
	err = m.Up()
	if err != nil {
		if err.Error() == "no change" {
			log.Debug().Msg("No Changes at Migration")
		} else {
			panic(err)
		}
	}
	log.Info().Msg("Run Migration done")
}

func sqlConnect() {
	log.Info().Msg("Connect to MYSQL Server")
	db, err := sqlx.Open("mysql", os.Getenv("DB_CONNECTION"))
	if err != nil {
		panic(err)
	}
	sqlConnection = db
	log.Debug().Msg("Connection to MYSQL Done")
}

func s3Connect() {
	log.Debug().Msg("Connect to s3")
	minioClient, err := minio.New( os.Getenv("S3_HOST"), &minio.Options{
		Creds:  credentials.NewStaticV4(os.Getenv("S3_ID"), os.Getenv("S3_SECRET"), os.Getenv("S3_TOKEN")),
		Secure: false,
	})
	if err != nil {
		log.Fatal().Err(err).Msg("Cant create s3 client")
	}


	s3 = minioClient

	log.Debug().Msg("Finish create s3 client")
}
func loadEnvConfig()  {
	err := godotenv.Load()
	if err != nil {
		log.Fatal().Err(err).Msg("Error loading .env file")
	}
}

func main() {
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
	loadEnvConfig()
	migrateDB()
	sqlConnect()
	s3Connect()

	f := flamego.Classic()
	f.Use(flamego.Static(
		flamego.StaticOptions{
			FileSystem: http.FS(public),
		},
	))
	f.Use(template.Templater(
		template.Options{

		},
	))
	ro := redis.Options{
		Addr:               os.Getenv("REDIS_HORST"),
		DB:                  os.Getenv("REDIS_DB").(int),
	}
	f.Use(session.Sessioner(session.Options{
		Initer: sredis.Initer(),
		Config: sredis.Config{
			Options: &ro,
		},
	}))

	f.Use(globaleuserdata.GlobalUserData(sqlConnection))

	f.Use(captcha.Captchaer(captcha.Options{
		TextLength: 4,
	}))

	f.Use(cors.CORS())

	f.Any("/", func(s session.Session, t template.Template, data template.Data) {
		t.HTML(http.StatusOK, "home")
	})

	f.Get("/login", loginForm)
	f.Post("/login", login)
	f.Get("/register", registerForm)
	f.Post("/register", register)
	f.Get("/logout", logout)

	f.Get("/gallery/new", galleryNewForm)
	f.Post("/gallery/new", galleryNew)

	f.Get("/gallery/edit", galleryEdit)

	f.Get("/file/upload", uploadImageForm)
	f.Post("/file/upload", uploadImage)

	f.Get("/u/{name}", userProfile)
	f.Get("/u/{name}/{id}", userGallery)
	f.Get("/image", getImage)

	f.Get("/settings/profile", profile)
	f.Post("/settings/profile", profileUpdate)
	f.Get("/settings/profile/image", profileImage)
	f.Post("/settings/profile/image", profileImageChange)
	f.Run()
}

