package domain

import (
	"fmt"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	domainAuth "github.com/haydenhargreaves/Potion/internal/domain/auth"
	domainEngagement "github.com/haydenhargreaves/Potion/internal/domain/engagement"
	domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
	domainUser "github.com/haydenhargreaves/Potion/internal/domain/user"
	"github.com/joho/godotenv"
)

// EnvironmentConfig stores the configuration of the environment. Anything loaded from the .env
// or docker environment will be stored here and can be accessed from the InjectedDependencies
// struct, which this is attached to.
type EnvironmentConfig struct {
	GoogleClientId     string
	GoogleClientSecret string
	JwtSecret          string
	DatabaseUrl        string
	Environment        string
	Domain             string
}

// InjectedDependencies is a collection of dependencies that are injected into the application. They
// are stored in the context and can be accessed by handlers via the context.
type InjectedDependencies struct {
	UserService       domainUser.UserService
	AuthService       domainAuth.AuthService
	RecipeService     domainRecipe.RecipeService
	EngagementService domainEngagement.EngagementService
	EnvironmentConfig EnvironmentConfig
}

// JwtClaims is the data stored in the JSON web token. All that is needed is the users ID and their
// Google email provided.
type JwtClaims struct {
	UserId int    `json:"id"`
	Email  string `json:"email"`
	jwt.RegisteredClaims
}

// IsLoggedIn checks the cookies in a request and returns whether the user is logged in.
func IsLoggedIn(ctx *gin.Context) bool {
	_, id := ctx.Get("userId")
	_, email := ctx.Get("userEmail")
	return id && email
}

func LoadEnvironment() (*EnvironmentConfig, error) {
	err := godotenv.Load(".env")
	if err != nil {
		fmt.Printf("No .env file found or error loading .env: %v. Relying on system environment variables.", err)
	}

	env := os.Getenv("ENVIRONMENT")
	if env == "" {
		return nil, fmt.Errorf("ENVIRONMENT environment variable is required.")
	}

	googleClientId := os.Getenv("GOOGLE_CLIENT_ID")
	if googleClientId == "" {
		return nil, fmt.Errorf("GOOGLE_CLIENT_ID environment variable is required.")
	}

	googleClientSecret := os.Getenv("GOOGLE_CLIENT_SECRET")
	if googleClientSecret == "" {
		return nil, fmt.Errorf("GOOGLE_CLIENT_SECRET environment variable is required.")
	}

	jwtSecret := os.Getenv("JWT_SECRET")
	if jwtSecret == "" {
		return nil, fmt.Errorf("JWT_SECRET environment variable is required.")
	}

	var domain string
	if env == "dev" {
		domain = os.Getenv("DOMAIN_DEV")
		if domain == "" {
			return nil, fmt.Errorf("DOMAIN_DEV environment variable is required when ENVIRONMENT is 'dev'.")
		}
	} else if env == "prod" {
		domain = os.Getenv("DOMAIN_PROD")
		if domain == "" {
			return nil, fmt.Errorf("DOMAIN_PROD environment variable is required when ENVIRONMENT is 'prod'.")
		}
	} else {
		return nil, fmt.Errorf("ENVIRONMENT environment variable is required and must be 'dev' or 'prod'.")
	}

	var dbUrl string
	if env == "dev" {
		dbUrl = os.Getenv("DATABASE_URL_DEV")
		if dbUrl == "" {
			return nil, fmt.Errorf("DATABASE_URL_DEV environment variable is required when ENVIRONMENT is 'dev'.")
		}
	} else if env == "prod" {
		dbUrl = os.Getenv("DATABASE_URL_PROD")
		if dbUrl == "" {
			return nil, fmt.Errorf("DATABASE_URL_PROD environment variable is required when ENVIRONMENT is 'prod'.")
		}
	} else {
		return nil, fmt.Errorf("ENVIRONMENT environment variable is required and must be 'dev' or 'prod'.")
	}

	cfg := &EnvironmentConfig{
		GoogleClientId:     googleClientId,
		GoogleClientSecret: googleClientSecret,
		JwtSecret:          jwtSecret,
		DatabaseUrl:        dbUrl,
		Environment:        env,
		Domain:             domain,
	}

	return cfg, nil
}
