package repository

import (
	"context"
	"sno/internal/models"
	"sno/internal/types"

	"github.com/jackc/pgx/v5/pgxpool"
)

// AdminRepository handles database operations for admins
type AdminRepository interface {
	GetByTelegramID(ctx context.Context, telegramID int64) (*models.Admin, error)
	Create(ctx context.Context, admin *models.Admin) error
	Update(ctx context.Context, admin *models.Admin) error
	Delete(ctx context.Context, telegramID int64) error
	ListAll(ctx context.Context) ([]*models.Admin, error)
	GetUserRole(ctx context.Context, telegramID int64) (types.UserRole, error)
}

// adminRepository implements AdminRepository interface
type adminRepository struct {
	db *pgxpool.Pool
}

// NewAdminRepository creates a new admin repository
func NewAdminRepository(db *pgxpool.Pool) AdminRepository {
	return &adminRepository{db: db}
}

// GetByTelegramID retrieves an admin by Telegram ID
func (r *adminRepository) GetByTelegramID(ctx context.Context, telegramID int64) (*models.Admin, error) {
	query := `
		SELECT telegram_id, role, name, added_by, added_at
		FROM admins
		WHERE telegram_id = $1
	`

	var admin models.Admin
	err := r.db.QueryRow(ctx, query, telegramID).Scan(
		&admin.TelegramID,
		&admin.Role,
		&admin.Name,
		&admin.AddedBy,
		&admin.AddedAt,
	)

	if err != nil {
		if err.Error() == "no rows in result set" {
			return nil, nil // Admin not found
		}
		return nil, err
	}

	return &admin, nil
}

// Create creates a new admin record
func (r *adminRepository) Create(ctx context.Context, admin *models.Admin) error {
	query := `
		INSERT INTO admins (telegram_id, role, name, added_by)
		VALUES ($1, $2, $3, $4)
		RETURNING added_at
	`

	return r.db.QueryRow(ctx, query,
		admin.TelegramID,
		admin.Role,
		admin.Name,
		admin.AddedBy,
	).Scan(&admin.AddedAt)
}

// Update updates an admin record
func (r *adminRepository) Update(ctx context.Context, admin *models.Admin) error {
	query := `
		UPDATE admins
		SET role = $2, name = $3
		WHERE telegram_id = $1
	`

	_, err := r.db.Exec(ctx, query,
		admin.TelegramID,
		admin.Role,
		admin.Name,
	)

	return err
}

// Delete deletes an admin record
func (r *adminRepository) Delete(ctx context.Context, telegramID int64) error {
	query := `DELETE FROM admins WHERE telegram_id = $1`
	_, err := r.db.Exec(ctx, query, telegramID)
	return err
}

// ListAll retrieves all admins
func (r *adminRepository) ListAll(ctx context.Context) ([]*models.Admin, error) {
	query := `
		SELECT telegram_id, role, name, added_by, added_at
		FROM admins
		ORDER BY added_at DESC
	`

	rows, err := r.db.Query(ctx, query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var admins []*models.Admin
	for rows.Next() {
		var admin models.Admin
		err := rows.Scan(
			&admin.TelegramID,
			&admin.Role,
			&admin.Name,
			&admin.AddedBy,
			&admin.AddedAt,
		)
		if err != nil {
			return nil, err
		}
		admins = append(admins, &admin)
	}

	return admins, nil
}

// GetUserRole retrieves user role from admins table
func (r *adminRepository) GetUserRole(ctx context.Context, telegramID int64) (types.UserRole, error) {
	query := `
		SELECT role
		FROM admins
		WHERE telegram_id = $1
	`

	var role models.AdminRole
	err := r.db.QueryRow(ctx, query, telegramID).Scan(&role)
	if err != nil {
		if err.Error() == "no rows in result set" {
			return types.RoleUser, nil // User is not an admin
		}
		return "", err
	}

	// Convert models.AdminRole to types.UserRole
	switch role {
	case models.RoleAdmin:
		return types.RoleAdmin, nil
	case models.RoleOperator:
		return types.RoleOperator, nil
	default:
		return types.RoleUser, nil
	}
}