package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/gdamore/tcell/v2"
	"github.com/jmoiron/sqlx"
	"github.com/rivo/tview"
	flag "github.com/spf13/pflag"
	_ "github.com/lib/pq"

	"github.com/ajaxray/geek-life/auth"
	"github.com/ajaxray/geek-life/config"
	"github.com/ajaxray/geek-life/migration"
	"github.com/ajaxray/geek-life/model"
	"github.com/ajaxray/geek-life/repository"
	"github.com/ajaxray/geek-life/repository/postgres"
	"github.com/ajaxray/geek-life/util"
)

var (
	app              *tview.Application
	layout, contents *tview.Flex

	statusBar         *StatusBar
	projectPane       *ProjectPane
	taskPane          *TaskPane
	taskDetailPane    *TaskDetailPane
	projectDetailPane *ProjectDetailPane

	db          *sqlx.DB
	projectRepo repository.ProjectRepository
	taskRepo    repository.TaskRepository
	authService *auth.AuthService
	userContext *model.UserContext

	// Configuration
	cfg *config.Config

	// Flag variables
	migrate bool
)

func init() {
	flag.BoolVarP(&migrate, "migrate", "m", false, "Run database migrations")
}

func main() {
	flag.Parse()

	// Load configuration
	var err error
	cfg, err = config.Load()
	if err != nil {
		log.Fatalf("Failed to load configuration: %v", err)
	}

	// Connect to PostgreSQL
	db, err = sqlx.Connect("postgres", cfg.GetDSN())
	if err != nil {
		log.Fatalf("Failed to connect to database: %v", err)
	}
	defer db.Close()

	// Run migrations if requested
	if migrate {
		migrator := migration.NewMigrator(db, "migrations")
		if err := migrator.Run(); err != nil {
			log.Fatalf("Failed to run migrations: %v", err)
		}
		fmt.Println("Migrations completed successfully")
		return
	}

	// Initialize repositories
	userRepo := postgres.NewUserRepository(db)
	tenantRepo := postgres.NewTenantRepository(db)
	sessionRepo := postgres.NewSessionRepository(db)
	projectRepo = postgres.NewProjectRepository(db)
	taskRepo = postgres.NewTaskRepository(db)

	// Initialize auth service
	authService = auth.NewAuthService(userRepo, tenantRepo, sessionRepo, cfg.Auth.SessionDuration)

	// Check for existing session
	sessionToken := loadSessionToken()
	if sessionToken != "" {
		userContext, err = authService.ValidateSession(sessionToken)
		if err != nil {
			// Invalid session, remove it
			removeSessionToken()
			sessionToken = ""
		}
	}

	// If no valid session, show login screen
	if userContext == nil {
		showAuthScreen()
		return
	}

	// Initialize and start the main application
	startMainApp()
}

func showAuthScreen() {
	app = tview.NewApplication()

	// Create auth form
	form := tview.NewForm()
	form.SetBorder(true).SetTitle("Geek-Life Authentication")

	var tenantName, username, password string
	var isLogin bool = true

	form.AddInputField("Tenant", "", 20, nil, func(text string) {
		tenantName = text
	})
	form.AddInputField("Username/Email", "", 20, nil, func(text string) {
		username = text
	})
	form.AddPasswordField("Password", "", 20, '*', func(text string) {
		password = text
	})

	form.AddButton("Login", func() {
		if tenantName == "" || username == "" || password == "" {
			showError("All fields are required")
			return
		}

		ctx, token, err := authService.Login(tenantName, username, password)
		if err != nil {
			showError(fmt.Sprintf("Login failed: %v", err))
			return
		}

		userContext = ctx
		saveSessionToken(token)
		app.Stop()
		startMainApp()
	})

	form.AddButton("Register User", func() {
		if tenantName == "" || username == "" || password == "" {
			showError("All fields are required")
			return
		}

		ctx, token, err := authService.RegisterUser(tenantName, username, username, password)
		if err != nil {
			showError(fmt.Sprintf("Registration failed: %v", err))
			return
		}

		userContext = ctx
		saveSessionToken(token)
		app.Stop()
		startMainApp()
	})

	form.AddButton("Register Tenant", func() {
		if tenantName == "" || username == "" || password == "" {
			showError("All fields are required")
			return
		}

		ctx, token, err := authService.RegisterTenant(tenantName, username, username, password)
		if err != nil {
			showError(fmt.Sprintf("Tenant registration failed: %v", err))
			return
		}

		userContext = ctx
		saveSessionToken(token)
		app.Stop()
		startMainApp()
	})

	form.AddButton("Quit", func() {
		app.Stop()
	})

	// Create info text
	info := tview.NewTextView()
	info.SetText("Welcome to Geek-Life!\n\n" +
		"• Login: Use existing tenant and user credentials\n" +
		"• Register User: Create a new user in an existing tenant\n" +
		"• Register Tenant: Create a new tenant with admin user\n\n" +
		"Use Tab to navigate between fields")
	info.SetBorder(true).SetTitle("Instructions")

	// Layout
	flex := tview.NewFlex().SetDirection(tview.FlexRow)
	flex.AddItem(info, 8, 0, false)
	flex.AddItem(form, 0, 1, true)

	if err := app.SetRoot(flex, true).EnableMouse(true).Run(); err != nil {
		panic(err)
	}
}

func startMainApp() {
	app = tview.NewApplication()

	statusBar = NewStatusBar(fmt.Sprintf("User: %s | Tenant: %s", userContext.User.Username, userContext.Tenant.Name))
	projectPane = NewProjectPane(userContext)
	taskPane = NewTaskPane(userContext)
	taskDetailPane = NewTaskDetailPane(userContext)
	projectDetailPane = NewProjectDetailPane(userContext)

	layout = tview.NewFlex().SetDirection(tview.FlexRow).
		AddItem(tview.NewFlex().SetDirection(tview.FlexColumn).
			AddItem(projectPane.GetView(), 25, 1, true).
			AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
				AddItem(taskPane.GetView(), 0, 7, false).
				AddItem(taskDetailPane.GetView(), 0, 3, false), 0, 5, false).
			AddItem(projectDetailPane.GetView(), 0, 2, false), 0, 1, true).
		AddItem(statusBar.GetView(), 1, 1, false)

	app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyCtrlC {
			app.Stop()
			return nil
		}
		if event.Key() == tcell.KeyCtrlL {
			// Logout
			sessionToken := loadSessionToken()
			if sessionToken != "" {
				authService.Logout(sessionToken)
				removeSessionToken()
			}
			app.Stop()
			userContext = nil
			showAuthScreen()
			return nil
		}
		return event
	})

	if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil {
		panic(err)
	}
}

func showError(message string) {
	modal := tview.NewModal().
		SetText(message).
		AddButtons([]string{"OK"}).
		SetDoneFunc(func(buttonIndex int, buttonLabel string) {
			app.SetRoot(app.GetRoot(), true)
		})
	app.SetRoot(modal, false)
}

func saveSessionToken(token string) {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return
	}
	
	sessionFile := filepath.Join(homeDir, ".geek-life-session")
	os.WriteFile(sessionFile, []byte(token), 0600)
}

func loadSessionToken() string {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return ""
	}
	
	sessionFile := filepath.Join(homeDir, ".geek-life-session")
	data, err := os.ReadFile(sessionFile)
	if err != nil {
		return ""
	}
	
	return string(data)
}

func removeSessionToken() {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return
	}
	
	sessionFile := filepath.Join(homeDir, ".geek-life-session")
	os.Remove(sessionFile)
}