package postgres

import (
	"context"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

type EnterpriseCardAuthorizationStore struct {
	db    *gorm.DB
	redis *redis.Client
}

func NewEnterpriseCardAuthorizationStore(db *gorm.DB, redis *redis.Client) *EnterpriseCardAuthorizationStore {
	return &EnterpriseCardAuthorizationStore{
		db:    db,
		redis: redis,
	}
}

func (s *EnterpriseCardAuthorizationStore) Create(ctx context.Context, auth *model.EnterpriseCardAuthorization) error {
	return s.db.WithContext(ctx).Create(auth).Error
}

func (s *EnterpriseCardAuthorizationStore) BatchCreate(ctx context.Context, auths []*model.EnterpriseCardAuthorization) error {
	if len(auths) == 0 {
		return nil
	}
	return s.db.WithContext(ctx).CreateInBatches(auths, 100).Error
}

func (s *EnterpriseCardAuthorizationStore) RevokeAuthorizations(ctx context.Context, enterpriseID uint, cardIDs []uint, revokedBy uint) error {
	if len(cardIDs) == 0 {
		return nil
	}
	now := time.Now()
	return s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
		Where("enterprise_id = ? AND card_id IN ? AND revoked_at IS NULL", enterpriseID, cardIDs).
		Updates(map[string]interface{}{
			"revoked_by": revokedBy,
			"revoked_at": now,
		}).Error
}

func (s *EnterpriseCardAuthorizationStore) GetByEnterpriseAndCard(ctx context.Context, enterpriseID, cardID uint) (*model.EnterpriseCardAuthorization, error) {
	var auth model.EnterpriseCardAuthorization
	query := s.db.WithContext(ctx).
		Where("enterprise_id = ? AND card_id = ?", enterpriseID, cardID)
	// 应用数据权限过滤
	query = s.applyEnterpriseAuthFilter(ctx, query)
	err := query.First(&auth).Error
	if err != nil {
		return nil, err
	}
	return &auth, nil
}

func (s *EnterpriseCardAuthorizationStore) ListByEnterprise(ctx context.Context, enterpriseID uint, includeRevoked bool) ([]*model.EnterpriseCardAuthorization, error) {
	var auths []*model.EnterpriseCardAuthorization
	query := s.db.WithContext(ctx).Where("enterprise_id = ?", enterpriseID)
	// 应用数据权限过滤
	query = s.applyEnterpriseAuthFilter(ctx, query)
	if !includeRevoked {
		query = query.Where("revoked_at IS NULL")
	}
	if err := query.Find(&auths).Error; err != nil {
		return nil, err
	}
	return auths, nil
}

func (s *EnterpriseCardAuthorizationStore) ListByCards(ctx context.Context, cardIDs []uint, includeRevoked bool) ([]*model.EnterpriseCardAuthorization, error) {
	if len(cardIDs) == 0 {
		return []*model.EnterpriseCardAuthorization{}, nil
	}
	var auths []*model.EnterpriseCardAuthorization
	query := s.db.WithContext(ctx).Where("card_id IN ?", cardIDs)
	// 应用数据权限过滤
	query = s.applyEnterpriseAuthFilter(ctx, query)
	if !includeRevoked {
		query = query.Where("revoked_at IS NULL")
	}
	if err := query.Find(&auths).Error; err != nil {
		return nil, err
	}
	return auths, nil
}

func (s *EnterpriseCardAuthorizationStore) GetActiveAuthorizedCardIDs(ctx context.Context, enterpriseID uint) ([]uint, error) {
	var cardIDs []uint
	query := s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
		Where("enterprise_id = ? AND revoked_at IS NULL", enterpriseID)
	// 应用数据权限过滤
	query = s.applyEnterpriseAuthFilter(ctx, query)
	err := query.Pluck("card_id", &cardIDs).Error
	return cardIDs, err
}

func (s *EnterpriseCardAuthorizationStore) CheckAuthorizationExists(ctx context.Context, enterpriseID, cardID uint) (bool, error) {
	var count int64
	query := s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
		Where("enterprise_id = ? AND card_id = ? AND revoked_at IS NULL", enterpriseID, cardID)
	// 应用数据权限过滤
	query = s.applyEnterpriseAuthFilter(ctx, query)
	err := query.Count(&count).Error
	return count > 0, err
}

type AuthorizationListOptions struct {
	EnterpriseID   *uint
	AuthorizerType *int
	AuthorizedBy   *uint
	IncludeRevoked bool
	CardIDs        []uint
	Offset         int
	Limit          int
}

func (s *EnterpriseCardAuthorizationStore) ListWithOptions(ctx context.Context, opts AuthorizationListOptions) ([]*model.EnterpriseCardAuthorization, int64, error) {
	var auths []*model.EnterpriseCardAuthorization
	query := s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{})
	// 应用数据权限过滤
	query = s.applyEnterpriseAuthFilter(ctx, query)

	if opts.EnterpriseID != nil {
		query = query.Where("enterprise_id = ?", *opts.EnterpriseID)
	}
	if opts.AuthorizerType != nil {
		query = query.Where("authorizer_type = ?", *opts.AuthorizerType)
	}
	if opts.AuthorizedBy != nil {
		query = query.Where("authorized_by = ?", *opts.AuthorizedBy)
	}
	if !opts.IncludeRevoked {
		query = query.Where("revoked_at IS NULL")
	}
	if len(opts.CardIDs) > 0 {
		query = query.Where("card_id IN ?", opts.CardIDs)
	}

	var total int64
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	if opts.Limit > 0 {
		query = query.Limit(opts.Limit).Offset(opts.Offset)
	}

	if err := query.Order("id DESC").Find(&auths).Error; err != nil {
		return nil, 0, err
	}

	return auths, total, nil
}

// GetActiveAuthsByCardIDs 获取指定企业和卡ID列表的有效授权记录（返回 map[cardID]bool）
func (s *EnterpriseCardAuthorizationStore) GetActiveAuthsByCardIDs(ctx context.Context, enterpriseID uint, cardIDs []uint) (map[uint]bool, error) {
	if len(cardIDs) == 0 {
		return make(map[uint]bool), nil
	}
	var authCardIDs []uint
	query := s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
		Where("enterprise_id = ? AND card_id IN ? AND revoked_at IS NULL", enterpriseID, cardIDs)
	// 应用数据权限过滤
	query = s.applyEnterpriseAuthFilter(ctx, query)
	err := query.Pluck("card_id", &authCardIDs).Error
	if err != nil {
		return nil, err
	}
	result := make(map[uint]bool)
	for _, cardID := range authCardIDs {
		result[cardID] = true
	}
	return result, nil
}

// GetConflictingAuthsByCardIDs 查询与指定企业冲突的有效授权（已被其他企业授权的卡）
// 不受数据权限过滤，专用于授权前的冲突检测
func (s *EnterpriseCardAuthorizationStore) GetConflictingAuthsByCardIDs(ctx context.Context, enterpriseID uint, cardIDs []uint) (map[uint]uint, error) {
	if len(cardIDs) == 0 {
		return make(map[uint]uint), nil
	}
	var auths []struct {
		CardID       uint
		EnterpriseID uint
	}
	err := s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
		Select("card_id, enterprise_id").
		Where("card_id IN ? AND enterprise_id != ? AND revoked_at IS NULL AND deleted_at IS NULL", cardIDs, enterpriseID).
		Scan(&auths).Error
	if err != nil {
		return nil, err
	}
	result := make(map[uint]uint, len(auths))
	for _, a := range auths {
		result[a.CardID] = a.EnterpriseID
	}
	return result, nil
}

// GetActiveAuthEnterpriseByCardIDs 获取卡ID列表的有效授权企业映射（cardID -> enterpriseID），不受数据权限过滤
func (s *EnterpriseCardAuthorizationStore) GetActiveAuthEnterpriseByCardIDs(ctx context.Context, cardIDs []uint) (map[uint]uint, error) {
	if len(cardIDs) == 0 {
		return make(map[uint]uint), nil
	}
	var auths []struct {
		CardID       uint
		EnterpriseID uint
	}
	err := s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
		Select("card_id, enterprise_id").
		Where("card_id IN ? AND revoked_at IS NULL AND deleted_at IS NULL", cardIDs).
		Scan(&auths).Error
	if err != nil {
		return nil, err
	}
	result := make(map[uint]uint, len(auths))
	for _, a := range auths {
		result[a.CardID] = a.EnterpriseID
	}
	return result, nil
}

// BatchUpdateStatus 批量更新授权状态（回收授权：设置 revoked_at）
func (s *EnterpriseCardAuthorizationStore) BatchUpdateStatus(ctx context.Context, enterpriseID uint, cardIDs []uint, status int) error {
	if len(cardIDs) == 0 {
		return nil
	}
	// status 0 表示回收（设置 revoked_at）
	if status == 0 {
		now := time.Now()
		return s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
			Where("enterprise_id = ? AND card_id IN ? AND revoked_at IS NULL", enterpriseID, cardIDs).
			Update("revoked_at", now).Error
	}
	// 其他状态暂不处理
	return nil
}

// ListCardIDsByEnterprise 获取企业的有效授权卡ID列表
func (s *EnterpriseCardAuthorizationStore) ListCardIDsByEnterprise(ctx context.Context, enterpriseID uint) ([]uint, error) {
	var cardIDs []uint
	query := s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
		Where("enterprise_id = ? AND revoked_at IS NULL", enterpriseID)
	// 应用数据权限过滤
	query = s.applyEnterpriseAuthFilter(ctx, query)
	err := query.Pluck("card_id", &cardIDs).Error
	return cardIDs, err
}

type AuthorizationWithJoinListOptions struct {
	EnterpriseID   *uint
	ICCID          string
	AuthorizerType *int
	Status         *int
	StartTime      *time.Time
	EndTime        *time.Time
	Offset         int
	Limit          int
}

type AuthorizationWithJoin struct {
	ID             uint       `gorm:"column:id"`
	EnterpriseID   uint       `gorm:"column:enterprise_id"`
	EnterpriseName string     `gorm:"column:enterprise_name"`
	CardID         uint       `gorm:"column:card_id"`
	ICCID          string     `gorm:"column:iccid"`
	MSISDN         string     `gorm:"column:msisdn"`
	AuthorizedBy   uint       `gorm:"column:authorized_by"`
	AuthorizerName string     `gorm:"column:authorizer_name"`
	AuthorizerType int        `gorm:"column:authorizer_type"`
	AuthorizedAt   time.Time  `gorm:"column:authorized_at"`
	RevokedBy      *uint      `gorm:"column:revoked_by"`
	RevokerName    *string    `gorm:"column:revoker_name"`
	RevokedAt      *time.Time `gorm:"column:revoked_at"`
	Remark         string     `gorm:"column:remark"`
}

func (s *EnterpriseCardAuthorizationStore) ListWithJoin(ctx context.Context, opts AuthorizationWithJoinListOptions) ([]AuthorizationWithJoin, int64, error) {
	baseQuery := `
		FROM tb_enterprise_card_authorization a
		LEFT JOIN tb_enterprise e ON a.enterprise_id = e.id AND e.deleted_at IS NULL
		LEFT JOIN tb_iot_card c ON a.card_id = c.id AND c.deleted_at IS NULL
		LEFT JOIN tb_account acc1 ON a.authorized_by = acc1.id AND acc1.deleted_at IS NULL
		LEFT JOIN tb_account acc2 ON a.revoked_by = acc2.id AND acc2.deleted_at IS NULL
		WHERE a.deleted_at IS NULL
	`

	args := []interface{}{}

	// 数据权限过滤（原生 SQL 需要手动处理）
	userType := middleware.GetUserTypeFromContext(ctx)
	// 超级管理员和平台用户跳过过滤
	if userType != constants.UserTypeSuperAdmin && userType != constants.UserTypePlatform {
		if userType == constants.UserTypeAgent {
			// 代理用户：只能看到自己及下级店铺所拥有企业的授权记录
			shopIDs := middleware.GetSubordinateShopIDs(ctx)
			if len(shopIDs) == 0 {
				// 代理用户没有下级店铺信息，返回空结果
				return []AuthorizationWithJoin{}, 0, nil
			}
			baseQuery += " AND a.enterprise_id IN (SELECT id FROM tb_enterprise WHERE owner_shop_id IN (?) AND deleted_at IS NULL)"
			args = append(args, shopIDs)
		} else if userType == constants.UserTypeEnterprise {
			enterpriseID := middleware.GetEnterpriseIDFromContext(ctx)
			if enterpriseID == 0 {
				return []AuthorizationWithJoin{}, 0, nil
			}
			baseQuery += " AND a.enterprise_id = ?"
			args = append(args, enterpriseID)
		} else {
			// 其他用户类型（个人客户等）不应访问授权记录
			return []AuthorizationWithJoin{}, 0, nil
		}
	}

	if opts.EnterpriseID != nil {
		baseQuery += " AND a.enterprise_id = ?"
		args = append(args, *opts.EnterpriseID)
	}
	if opts.ICCID != "" {
		baseQuery += " AND c.iccid LIKE ?"
		args = append(args, "%"+opts.ICCID+"%")
	}
	if opts.AuthorizerType != nil {
		baseQuery += " AND a.authorizer_type = ?"
		args = append(args, *opts.AuthorizerType)
	}
	if opts.Status != nil {
		if *opts.Status == 1 {
			baseQuery += " AND a.revoked_at IS NULL"
		} else {
			baseQuery += " AND a.revoked_at IS NOT NULL"
		}
	}
	if opts.StartTime != nil {
		baseQuery += " AND a.authorized_at >= ?"
		args = append(args, *opts.StartTime)
	}
	if opts.EndTime != nil {
		baseQuery += " AND a.authorized_at < ?"
		args = append(args, *opts.EndTime)
	}

	var total int64
	countSQL := "SELECT COUNT(*) " + baseQuery
	if err := s.db.WithContext(ctx).Raw(countSQL, args...).Scan(&total).Error; err != nil {
		return nil, 0, err
	}

	selectSQL := `
		SELECT 
			a.id, a.enterprise_id, COALESCE(e.enterprise_name, '') as enterprise_name,
			a.card_id, COALESCE(c.iccid, '') as iccid, COALESCE(c.msisdn, '') as msisdn,
			a.authorized_by, COALESCE(acc1.username, '') as authorizer_name,
			a.authorizer_type, a.authorized_at,
			a.revoked_by, acc2.username as revoker_name, a.revoked_at,
			COALESCE(a.remark, '') as remark
	` + baseQuery + " ORDER BY a.id DESC"

	if opts.Limit > 0 {
		selectSQL += " LIMIT ? OFFSET ?"
		args = append(args, opts.Limit, opts.Offset)
	}

	var results []AuthorizationWithJoin
	if err := s.db.WithContext(ctx).Raw(selectSQL, args...).Scan(&results).Error; err != nil {
		return nil, 0, err
	}

	return results, total, nil
}

func (s *EnterpriseCardAuthorizationStore) GetByIDWithJoin(ctx context.Context, id uint) (*AuthorizationWithJoin, error) {
	baseSQL := `
		SELECT 
			a.id, a.enterprise_id, COALESCE(e.enterprise_name, '') as enterprise_name,
			a.card_id, COALESCE(c.iccid, '') as iccid, COALESCE(c.msisdn, '') as msisdn,
			a.authorized_by, COALESCE(acc1.username, '') as authorizer_name,
			a.authorizer_type, a.authorized_at,
			a.revoked_by, acc2.username as revoker_name, a.revoked_at,
			COALESCE(a.remark, '') as remark
		FROM tb_enterprise_card_authorization a
		LEFT JOIN tb_enterprise e ON a.enterprise_id = e.id AND e.deleted_at IS NULL
		LEFT JOIN tb_iot_card c ON a.card_id = c.id AND c.deleted_at IS NULL
		LEFT JOIN tb_account acc1 ON a.authorized_by = acc1.id AND acc1.deleted_at IS NULL
		LEFT JOIN tb_account acc2 ON a.revoked_by = acc2.id AND acc2.deleted_at IS NULL
		WHERE a.id = ? AND a.deleted_at IS NULL
	`

	args := []interface{}{id}

	// 数据权限过滤（原生 SQL 需要手动处理）
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType != constants.UserTypeSuperAdmin && userType != constants.UserTypePlatform {
		if userType == constants.UserTypeAgent {
			// 代理用户：只能看到自己及下级店铺所拥有企业的授权记录
			shopIDs := middleware.GetSubordinateShopIDs(ctx)
			if len(shopIDs) == 0 {
				return nil, gorm.ErrRecordNotFound
			}
			baseSQL += " AND a.enterprise_id IN (SELECT id FROM tb_enterprise WHERE owner_shop_id IN (?) AND deleted_at IS NULL)"
			args = append(args, shopIDs)
		} else if userType == constants.UserTypeEnterprise {
			enterpriseID := middleware.GetEnterpriseIDFromContext(ctx)
			if enterpriseID == 0 {
				return nil, gorm.ErrRecordNotFound
			}
			baseSQL += " AND a.enterprise_id = ?"
			args = append(args, enterpriseID)
		} else {
			return nil, gorm.ErrRecordNotFound
		}
	}

	var result AuthorizationWithJoin
	if err := s.db.WithContext(ctx).Raw(baseSQL, args...).Scan(&result).Error; err != nil {
		return nil, err
	}

	if result.ID == 0 {
		return nil, gorm.ErrRecordNotFound
	}

	return &result, nil
}

func (s *EnterpriseCardAuthorizationStore) UpdateRemark(ctx context.Context, id uint, remark string) error {
	result := s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
		Where("id = ?", id).
		Update("remark", remark)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return gorm.ErrRecordNotFound
	}
	return nil
}

func (s *EnterpriseCardAuthorizationStore) UpdateRemarkWithConstraint(ctx context.Context, id uint, remark string, authorizedBy uint) error {
	result := s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
		Where("id = ? AND authorized_by = ?", id, authorizedBy).
		Update("remark", remark)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return gorm.ErrRecordNotFound
	}
	return nil
}

func (s *EnterpriseCardAuthorizationStore) GetByID(ctx context.Context, id uint) (*model.EnterpriseCardAuthorization, error) {
	var auth model.EnterpriseCardAuthorization
	query := s.db.WithContext(ctx).Where("id = ?", id)
	// 应用数据权限过滤
	query = s.applyEnterpriseAuthFilter(ctx, query)
	err := query.First(&auth).Error
	if err != nil {
		return nil, err
	}
	return &auth, nil
}

func (s *EnterpriseCardAuthorizationStore) RevokeByDeviceAuthID(ctx context.Context, deviceAuthID uint, revokedBy uint) error {
	now := time.Now()
	return s.db.WithContext(ctx).Model(&model.EnterpriseCardAuthorization{}).
		Where("device_auth_id = ? AND revoked_at IS NULL", deviceAuthID).
		Updates(map[string]interface{}{
			"revoked_by": revokedBy,
			"revoked_at": now,
		}).Error
}

// applyEnterpriseAuthFilter 应用企业卡授权表的数据权限过滤
// 企业用户：只能看到自己企业的授权记录
// 代理用户：只能看到自己及下级店铺所拥有企业的授权记录
// 平台/超管：不过滤
func (s *EnterpriseCardAuthorizationStore) applyEnterpriseAuthFilter(ctx context.Context, query *gorm.DB) *gorm.DB {
	// 企业用户过滤
	query = middleware.ApplyEnterpriseFilter(ctx, query)

	// 代理用户：通过企业的 owner_shop_id 过滤
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType == constants.UserTypeAgent {
		shopIDs := middleware.GetSubordinateShopIDs(ctx)
		if shopIDs != nil {
			query = query.Where("enterprise_id IN (SELECT id FROM tb_enterprise WHERE owner_shop_id IN ? AND deleted_at IS NULL)", shopIDs)
		}
	}

	return query
}
