package main

import (
	"context"
	"database/sql"
	"fmt"
	"io"
	"os"
	"os/signal"

	"git.runcible.io/androiddrew/cookiecutter-golang-server/internal/logging"
	"git.runcible.io/androiddrew/cookiecutter-golang-server/internal/migrations"
)

// run serves as the "entrypoint" of the application
//
// Operating system fundamentals are passed into run as arguments.
// This makes your programs much easier to test because test code can
// call run to execute your program, controlling arguments, and all
// streams, just by passing different arguments.
//
// Value	Type	Description
// os.Args	[]string	The arguments passed in when executing your program. It’s also used for parsing flags.
// os.Stdin	io.Reader	For reading input
// os.Stdout	io.Writer	For writing output
// os.Stderr	io.Writer	For writing error and logs
// os.Getenv	func(string) string	For reading environment variables
// os.Getwd	func() (string, error)	Get the working directory
//
// If you keep away from any global scope data, you can usually use t.Parallel() in more places,
// to speed up your test suites. Everything is self-contained, so multiple calls to run don’t
// interfere with each other.
func run(ctx context.Context, w io.Writer, args []string) error {
	ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
	defer cancel()

	// Config
	// TODO add real config
	var dbPath string = "./app.db"

	logger := logging.InitLogging("INFO", w)
	logger.Info("I am alive!")

	full_database_path := "file:" + dbPath + "?cache=shared"

	logger.Debug(fmt.Sprintf("Using database path: %s", full_database_path))

	db, err := sql.Open("sqlite3", full_database_path)
	if err != nil {
		return fmt.Errorf("failed to open: %s", full_database_path)
	}

	err = migrations.Migrate(db, logger)
	if err != nil {
		return err
	}

	// Initialize server

	// Add middleware

	return nil
}

func main() {
	ctx := context.Background()
	if err := run(ctx, os.Stdout, os.Args); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
}