package auth

import (
	"context"
	"crypto/rand"
	"database/sql"
	"encoding/base64"
	"time"

	"github.com/google/uuid"
)

const (
	SessionCookieName = "session_token"
	SessionDuration   = 24 * time.Hour
)

type Session struct {
	ID        string
	UserID    string
	Token     string
	ExpiresAt time.Time
	CreatedAt time.Time
}

type SessionStore struct {
	DB *sql.DB
}

func NewSessionStore(db *sql.DB) *SessionStore {
	return &SessionStore{DB: db}
}

// GenerateToken generates a secure random token
func GenerateToken() (string, error) {
	b := make([]byte, 32)
	if _, err := rand.Read(b); err != nil {
		return "", err
	}
	return base64.URLEncoding.EncodeToString(b), nil
}

// CreateSession creates a new session for a user
func (s *SessionStore) CreateSession(ctx context.Context, userID string) (*Session, error) {
	token, err := GenerateToken()
	if err != nil {
		return nil, err
	}

	sessionID := uuid.New().String()
	expiresAt := time.Now().Add(SessionDuration)

	_, err = s.DB.ExecContext(ctx,
		`INSERT INTO sessions (id, user_id, token, expires_at) VALUES (?, ?, ?, ?)`,
		sessionID, userID, token, expiresAt)
	if err != nil {
		return nil, err
	}

	return &Session{
		ID:        sessionID,
		UserID:    userID,
		Token:     token,
		ExpiresAt: expiresAt,
		CreatedAt: time.Now(),
	}, nil
}

// GetSession retrieves a session by token
func (s *SessionStore) GetSession(ctx context.Context, token string) (*Session, error) {
	var session Session
	var expiresAtStr string
	err := s.DB.QueryRowContext(ctx,
		`SELECT id, user_id, token, expires_at, created_at FROM sessions WHERE token = ? AND expires_at > ?`,
		token, time.Now()).Scan(&session.ID, &session.UserID, &session.Token, &expiresAtStr, &session.CreatedAt)
	if err != nil {
		return nil, err
	}

	session.ExpiresAt, err = time.Parse("2006-01-02 15:04:05", expiresAtStr)
	if err != nil {
		// Try with timezone
		session.ExpiresAt, err = time.Parse(time.RFC3339, expiresAtStr)
		if err != nil {
			return nil, err
		}
	}

	return &session, nil
}

// DeleteSession deletes a session by token
func (s *SessionStore) DeleteSession(ctx context.Context, token string) error {
	_, err := s.DB.ExecContext(ctx, `DELETE FROM sessions WHERE token = ?`, token)
	return err
}

// DeleteUserSessions deletes all sessions for a user
func (s *SessionStore) DeleteUserSessions(ctx context.Context, userID string) error {
	_, err := s.DB.ExecContext(ctx, `DELETE FROM sessions WHERE user_id = ?`, userID)
	return err
}

// CleanupExpiredSessions removes expired sessions
func (s *SessionStore) CleanupExpiredSessions(ctx context.Context) error {
	_, err := s.DB.ExecContext(ctx, `DELETE FROM sessions WHERE expires_at < ?`, time.Now())
	return err
}
