package service

import (
	"database/sql"
	"fmt"
	"time"

	"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/models"

	_ "github.com/go-sql-driver/mysql" // Hanya menjalankan side-effectsnya saja dahulu
	"github.com/google/uuid"
	"github.com/jmoiron/sqlx"
)

// Repository provides an interface to the database
type Repository struct {
	db *sqlx.DB
}

// NewRepository creates a new database repository
func NewRepository(dsn string) (*Repository, error) {
	db, err := sqlx.Connect("mysql", dsn)
	if err != nil {
		return nil, fmt.Errorf("failed to connect to database: %w", err)
	}

	// Set connection pool settings
	db.SetMaxOpenConns(10)
	db.SetMaxIdleConns(5)
	db.SetConnMaxLifetime(time.Hour)

	return &Repository{
		db: db,
	}, nil
}

// GetUserByEmail retrieves a user by email
func (r *Repository) GetUserByEmail(email string) (*models.User, error) {
	var user models.User
	err := r.db.Get(&user, "SELECT * FROM users WHERE email = ?", email)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}
	return &user, nil
}

// GetUserByID retrieves a user by ID
func (r *Repository) GetUserByID(id string) (*models.User, error) {
	var user models.User
	err := r.db.Get(&user, "SELECT * FROM users WHERE id = ?", id)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}
	return &user, nil
}

// StoreRefreshToken saves a refresh token to the database
func (r *Repository) StoreRefreshToken(userID, token string, expiresAt time.Time) error {
	refreshToken := models.RefreshToken{
		ID:        uuid.New().String(),
		UserID:    userID,
		Token:     token,
		ExpiresAt: expiresAt.Format(time.RFC3339),
		IsRevoked: false,
		CreatedAt: time.Now().Format(time.RFC3339),
	}

	_, err := r.db.NamedExec(
		`INSERT INTO refresh_tokens (id, user_id, token, expires_at, is_revoked, created_at) 
		 VALUES (:id, :user_id, :token, :expires_at, :is_revoked, :created_at)`,
		refreshToken,
	)
	return err
}

// GetRefreshToken retrieves a refresh token from the database
func (r *Repository) GetRefreshToken(token string) (*models.RefreshToken, error) {
	var refreshToken models.RefreshToken
	err := r.db.Get(&refreshToken, "SELECT * FROM refresh_tokens WHERE token = ?", token)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}
	return &refreshToken, nil
}

// RevokeRefreshToken marks a refresh token as revoked
func (r *Repository) RevokeRefreshToken(token string) error {
	_, err := r.db.Exec("UPDATE refresh_tokens SET is_revoked = true WHERE token = ?", token)
	return err
}

// GetPatientDetails retrieves patient details for a user
func (r *Repository) GetPatientDetails(userID string) (*models.PatientDetails, error) {
	var patientDetails models.PatientDetails
	err := r.db.Get(&patientDetails, "SELECT * FROM patient_details WHERE user_id = ?", userID)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}
	return &patientDetails, nil
}

// GetDoctorDetails retrieves doctor details for a user
func (r *Repository) GetDoctorDetails(userID string) (*models.DoctorDetails, error) {
	var doctorDetails models.DoctorDetails
	err := r.db.Get(&doctorDetails, "SELECT * FROM doctor_details WHERE user_id = ?", userID)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}
	return &doctorDetails, nil
}

// Close closes the database connection
func (r *Repository) Close() error {
	return r.db.Close()
}
