package repository

import (
	"context"
	"database/sql"
	"fmt"

	gormsqlite "gorm.io/driver/sqlite"
	"gorm.io/gorm"

	"github.com/user-management-system/internal/domain"
)

// SocialAccountRepository 社交账号仓库接口
type SocialAccountRepository interface {
	Create(ctx context.Context, account *domain.SocialAccount) error
	Update(ctx context.Context, account *domain.SocialAccount) error
	Delete(ctx context.Context, id int64) error
	DeleteByProviderAndUserID(ctx context.Context, provider string, userID int64) error
	GetByID(ctx context.Context, id int64) (*domain.SocialAccount, error)
	GetByUserID(ctx context.Context, userID int64) ([]*domain.SocialAccount, error)
	GetByProviderAndOpenID(ctx context.Context, provider, openID string) (*domain.SocialAccount, error)
	List(ctx context.Context, offset, limit int) ([]*domain.SocialAccount, int64, error)
}

// SocialAccountRepositoryImpl 社交账号仓库实现
type SocialAccountRepositoryImpl struct {
	db *gorm.DB
}

// NewSocialAccountRepository 创建社交账号仓库。
// 仓库主实现统一基于 GORM；保留 *sql.DB 构造兼容仅用于当前仓库的 SQLite 测试场景。
func NewSocialAccountRepository(db interface{}) (SocialAccountRepository, error) {
	switch d := db.(type) {
	case *gorm.DB:
		if d == nil {
			return nil, fmt.Errorf("gorm db is nil")
		}
		return &SocialAccountRepositoryImpl{db: d}, nil
	case *sql.DB:
		if d == nil {
			return nil, fmt.Errorf("sql db is nil")
		}
		gormDB, err := gorm.Open(gormsqlite.New(gormsqlite.Config{
			Conn:       d,
			DriverName: "sqlite",
		}), &gorm.Config{})
		if err != nil {
			return nil, fmt.Errorf("wrap sql db with gorm failed: %w", err)
		}
		return &SocialAccountRepositoryImpl{db: gormDB}, nil
	default:
		return nil, fmt.Errorf("unsupported db type: %T", db)
	}
}

// Create 创建社交账号
func (r *SocialAccountRepositoryImpl) Create(ctx context.Context, account *domain.SocialAccount) error {
	return r.db.WithContext(ctx).Create(account).Error
}

// Update 更新社交账号
func (r *SocialAccountRepositoryImpl) Update(ctx context.Context, account *domain.SocialAccount) error {
	updates := map[string]interface{}{
		"union_id": account.UnionID,
		"nickname": account.Nickname,
		"avatar":   account.Avatar,
		"gender":   account.Gender,
		"email":    account.Email,
		"phone":    account.Phone,
		"extra":    account.Extra,
		"status":   account.Status,
	}

	return r.db.WithContext(ctx).
		Model(&domain.SocialAccount{}).
		Where("id = ?", account.ID).
		Updates(updates).Error
}

// Delete 删除社交账号
func (r *SocialAccountRepositoryImpl) Delete(ctx context.Context, id int64) error {
	return r.db.WithContext(ctx).Delete(&domain.SocialAccount{}, id).Error
}

// DeleteByProviderAndUserID 删除指定用户和提供商的社交账号
func (r *SocialAccountRepositoryImpl) DeleteByProviderAndUserID(ctx context.Context, provider string, userID int64) error {
	return r.db.WithContext(ctx).
		Where("provider = ? AND user_id = ?", provider, userID).
		Delete(&domain.SocialAccount{}).Error
}

// GetByID 根据ID获取社交账号
func (r *SocialAccountRepositoryImpl) GetByID(ctx context.Context, id int64) (*domain.SocialAccount, error) {
	var account domain.SocialAccount
	if err := r.db.WithContext(ctx).First(&account, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil
		}
		return nil, fmt.Errorf("failed to get social account: %w", err)
	}

	return &account, nil
}

// GetByUserID 根据用户ID获取社交账号列表
func (r *SocialAccountRepositoryImpl) GetByUserID(ctx context.Context, userID int64) ([]*domain.SocialAccount, error) {
	var accounts []*domain.SocialAccount
	if err := r.db.WithContext(ctx).
		Where("user_id = ?", userID).
		Order("created_at DESC").
		Find(&accounts).Error; err != nil {
		return nil, fmt.Errorf("failed to query social accounts: %w", err)
	}

	return accounts, nil
}

// GetByProviderAndOpenID 根据提供商和OpenID获取社交账号
func (r *SocialAccountRepositoryImpl) GetByProviderAndOpenID(ctx context.Context, provider, openID string) (*domain.SocialAccount, error) {
	var account domain.SocialAccount
	if err := r.db.WithContext(ctx).
		Where("provider = ? AND open_id = ?", provider, openID).
		First(&account).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil
		}
		return nil, fmt.Errorf("failed to get social account: %w", err)
	}

	return &account, nil
}

// List 分页获取社交账号列表
func (r *SocialAccountRepositoryImpl) List(ctx context.Context, offset, limit int) ([]*domain.SocialAccount, int64, error) {
	var accounts []*domain.SocialAccount
	var total int64
	query := r.db.WithContext(ctx).Model(&domain.SocialAccount{})

	if err := query.Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to count social accounts: %w", err)
	}
	if err := query.Order("created_at DESC").Offset(offset).Limit(limit).Find(&accounts).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to query social accounts: %w", err)
	}

	return accounts, total, nil
}
