package enterprise_card

import (
	"context"
	"fmt"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

type AuthorizationService struct {
	enterpriseStore    *postgres.EnterpriseStore
	iotCardStore       *postgres.IotCardStore
	authorizationStore *postgres.EnterpriseCardAuthorizationStore
	logger             *zap.Logger
}

func NewAuthorizationService(
	enterpriseStore *postgres.EnterpriseStore,
	iotCardStore *postgres.IotCardStore,
	authorizationStore *postgres.EnterpriseCardAuthorizationStore,
	logger *zap.Logger,
) *AuthorizationService {
	return &AuthorizationService{
		enterpriseStore:    enterpriseStore,
		iotCardStore:       iotCardStore,
		authorizationStore: authorizationStore,
		logger:             logger,
	}
}

type BatchAuthorizeRequest struct {
	EnterpriseID   uint
	CardIDs        []uint
	AuthorizerID   uint
	AuthorizerType int
	Remark         string
}

func (s *AuthorizationService) BatchAuthorize(ctx context.Context, req BatchAuthorizeRequest) error {
	if len(req.CardIDs) == 0 {
		return errors.New(errors.CodeInvalidParam, "卡ID列表不能为空")
	}

	userID := middleware.GetUserIDFromContext(ctx)
	userType := middleware.GetUserTypeFromContext(ctx)
	shopID := middleware.GetShopIDFromContext(ctx)

	if userID == 0 {
		return errors.New(errors.CodeUnauthorized, "用户信息无效")
	}

	enterprise, err := s.enterpriseStore.GetByID(ctx, req.EnterpriseID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeEnterpriseNotFound, "企业不存在")
		}
		return err
	}

	if userType == constants.UserTypeAgent {
		if enterprise.OwnerShopID == nil || *enterprise.OwnerShopID != shopID {
			return errors.New(errors.CodeCannotAuthorizeToOthersEnterprise, "只能授权给自己的企业")
		}
	}

	cards, err := s.iotCardStore.GetByIDs(ctx, req.CardIDs)
	if err != nil {
		return err
	}

	if len(cards) != len(req.CardIDs) {
		return errors.New(errors.CodeIotCardNotFound, "部分卡不存在")
	}

	cardMap := make(map[uint]*model.IotCard)
	for _, card := range cards {
		cardMap[card.ID] = card
	}

	for _, cardID := range req.CardIDs {
		card := cardMap[cardID]

		if card.ShopID == nil {
			return errors.New(errors.CodeIotCardStatusNotAllowed, fmt.Sprintf("卡 %s 未分销，不能授权", card.ICCID))
		}

		if userType == constants.UserTypeAgent && *card.ShopID != shopID {
			return errors.New(errors.CodeCannotAuthorizeOthersCard, fmt.Sprintf("卡 %s 不属于您的店铺", card.ICCID))
		}
	}

	boundCardIDs, err := s.iotCardStore.GetBoundCardIDs(ctx, req.CardIDs)
	if err != nil {
		return err
	}
	if len(boundCardIDs) > 0 {
		return errors.New(errors.CodeCannotAuthorizeBoundCard, "部分卡已绑定设备，不能授权")
	}

	existingAuths, err := s.authorizationStore.ListByCards(ctx, req.CardIDs, false)
	if err != nil {
		return err
	}

	existingMap := make(map[uint]bool)
	for _, auth := range existingAuths {
		if auth.EnterpriseID == req.EnterpriseID {
			existingMap[auth.CardID] = true
		}
	}

	var newAuths []*model.EnterpriseCardAuthorization
	for _, cardID := range req.CardIDs {
		if existingMap[cardID] {
			continue
		}
		newAuths = append(newAuths, &model.EnterpriseCardAuthorization{
			EnterpriseID:   req.EnterpriseID,
			CardID:         cardID,
			AuthorizedBy:   req.AuthorizerID,
			AuthorizerType: req.AuthorizerType,
			Remark:         req.Remark,
		})
	}

	if len(newAuths) == 0 {
		return errors.New(errors.CodeCardAlreadyAuthorized, "所有卡已授权给该企业")
	}

	return s.authorizationStore.BatchCreate(ctx, newAuths)
}

type RevokeAuthorizationsRequest struct {
	EnterpriseID uint
	CardIDs      []uint
	RevokedBy    uint
}

func (s *AuthorizationService) RevokeAuthorizations(ctx context.Context, req RevokeAuthorizationsRequest) error {
	if len(req.CardIDs) == 0 {
		return errors.New(errors.CodeInvalidParam, "卡ID列表不能为空")
	}

	userID := middleware.GetUserIDFromContext(ctx)
	userType := middleware.GetUserTypeFromContext(ctx)

	if userID == 0 {
		return errors.New(errors.CodeUnauthorized, "用户信息无效")
	}

	existingAuths, err := s.authorizationStore.ListByCards(ctx, req.CardIDs, false)
	if err != nil {
		return err
	}

	authMap := make(map[uint]*model.EnterpriseCardAuthorization)
	for _, auth := range existingAuths {
		if auth.EnterpriseID == req.EnterpriseID {
			authMap[auth.CardID] = auth
		}
	}

	if len(authMap) == 0 {
		return errors.New(errors.CodeCardNotAuthorized, "卡未授权给该企业")
	}

	if userType == constants.UserTypeAgent {
		for _, auth := range authMap {
			if auth.AuthorizedBy != userID {
				return errors.New(errors.CodeCannotRevokeOthersAuthorization, "只能回收自己创建的授权")
			}
		}
	}

	var cardIDsToRevoke []uint
	for cardID := range authMap {
		cardIDsToRevoke = append(cardIDsToRevoke, cardID)
	}

	return s.authorizationStore.RevokeAuthorizations(ctx, req.EnterpriseID, cardIDsToRevoke, req.RevokedBy)
}

type ListAuthorizationsRequest struct {
	EnterpriseID   *uint
	AuthorizedBy   *uint
	IncludeRevoked bool
	Page           int
	PageSize       int
}

type ListAuthorizationsResponse struct {
	Authorizations []*model.EnterpriseCardAuthorization
	Total          int64
}

func (s *AuthorizationService) ListAuthorizations(ctx context.Context, req ListAuthorizationsRequest) (*ListAuthorizationsResponse, error) {
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = constants.DefaultPageSize
	}
	if req.PageSize > constants.MaxPageSize {
		req.PageSize = constants.MaxPageSize
	}

	opts := postgres.AuthorizationListOptions{
		EnterpriseID:   req.EnterpriseID,
		AuthorizedBy:   req.AuthorizedBy,
		IncludeRevoked: req.IncludeRevoked,
		Offset:         (req.Page - 1) * req.PageSize,
		Limit:          req.PageSize,
	}

	auths, total, err := s.authorizationStore.ListWithOptions(ctx, opts)
	if err != nil {
		return nil, err
	}

	return &ListAuthorizationsResponse{
		Authorizations: auths,
		Total:          total,
	}, nil
}

func (s *AuthorizationService) GetAuthorizedCardIDs(ctx context.Context, enterpriseID uint) ([]uint, error) {
	return s.authorizationStore.GetActiveAuthorizedCardIDs(ctx, enterpriseID)
}

type ListRecordsRequest struct {
	EnterpriseID   *uint
	ICCID          string
	AuthorizerType *int
	Status         *int
	StartTime      string
	EndTime        string
	Page           int
	PageSize       int
}

type AuthorizationRecord struct {
	ID             uint
	EnterpriseID   uint
	EnterpriseName string
	CardID         uint
	ICCID          string
	MSISDN         string
	AuthorizedBy   uint
	AuthorizerName string
	AuthorizerType int
	AuthorizedAt   string
	RevokedBy      *uint
	RevokerName    string
	RevokedAt      *string
	Status         int
	Remark         string
}

type ListRecordsResponse struct {
	Items []AuthorizationRecord
	Total int64
	Page  int
	Size  int
}

func (s *AuthorizationService) ListRecords(ctx context.Context, req ListRecordsRequest) (*ListRecordsResponse, error) {
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = constants.DefaultPageSize
	}
	if req.PageSize > constants.MaxPageSize {
		req.PageSize = constants.MaxPageSize
	}

	opts := postgres.AuthorizationWithJoinListOptions{
		EnterpriseID:   req.EnterpriseID,
		ICCID:          req.ICCID,
		AuthorizerType: req.AuthorizerType,
		Status:         req.Status,
		Offset:         (req.Page - 1) * req.PageSize,
		Limit:          req.PageSize,
	}

	if req.StartTime != "" {
		t, err := parseDate(req.StartTime)
		if err == nil {
			opts.StartTime = &t
		}
	}
	if req.EndTime != "" {
		t, err := parseDate(req.EndTime)
		if err == nil {
			endTime := t.AddDate(0, 0, 1)
			opts.EndTime = &endTime
		}
	}

	results, total, err := s.authorizationStore.ListWithJoin(ctx, opts)
	if err != nil {
		return nil, err
	}

	items := make([]AuthorizationRecord, len(results))
	for i, r := range results {
		status := 1
		if r.RevokedAt != nil {
			status = 0
		}

		var revokedAt *string
		if r.RevokedAt != nil {
			t := r.RevokedAt.Format("2006-01-02 15:04:05")
			revokedAt = &t
		}

		revokerName := ""
		if r.RevokerName != nil {
			revokerName = *r.RevokerName
		}

		items[i] = AuthorizationRecord{
			ID:             r.ID,
			EnterpriseID:   r.EnterpriseID,
			EnterpriseName: r.EnterpriseName,
			CardID:         r.CardID,
			ICCID:          r.ICCID,
			MSISDN:         r.MSISDN,
			AuthorizedBy:   r.AuthorizedBy,
			AuthorizerName: r.AuthorizerName,
			AuthorizerType: r.AuthorizerType,
			AuthorizedAt:   r.AuthorizedAt.Format("2006-01-02 15:04:05"),
			RevokedBy:      r.RevokedBy,
			RevokerName:    revokerName,
			RevokedAt:      revokedAt,
			Status:         status,
			Remark:         r.Remark,
		}
	}

	return &ListRecordsResponse{
		Items: items,
		Total: total,
		Page:  req.Page,
		Size:  req.PageSize,
	}, nil
}

func (s *AuthorizationService) GetRecordDetail(ctx context.Context, id uint) (*AuthorizationRecord, error) {
	r, err := s.authorizationStore.GetByIDWithJoin(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "授权记录不存在")
		}
		return nil, err
	}

	status := 1
	if r.RevokedAt != nil {
		status = 0
	}

	var revokedAt *string
	if r.RevokedAt != nil {
		t := r.RevokedAt.Format("2006-01-02 15:04:05")
		revokedAt = &t
	}

	revokerName := ""
	if r.RevokerName != nil {
		revokerName = *r.RevokerName
	}

	return &AuthorizationRecord{
		ID:             r.ID,
		EnterpriseID:   r.EnterpriseID,
		EnterpriseName: r.EnterpriseName,
		CardID:         r.CardID,
		ICCID:          r.ICCID,
		MSISDN:         r.MSISDN,
		AuthorizedBy:   r.AuthorizedBy,
		AuthorizerName: r.AuthorizerName,
		AuthorizerType: r.AuthorizerType,
		AuthorizedAt:   r.AuthorizedAt.Format("2006-01-02 15:04:05"),
		RevokedBy:      r.RevokedBy,
		RevokerName:    revokerName,
		RevokedAt:      revokedAt,
		Status:         status,
		Remark:         r.Remark,
	}, nil
}

func (s *AuthorizationService) UpdateRecordRemark(ctx context.Context, id uint, remark string) (*AuthorizationRecord, error) {
	userID := middleware.GetUserIDFromContext(ctx)
	userType := middleware.GetUserTypeFromContext(ctx)

	if userID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "用户信息无效")
	}

	record, err := s.authorizationStore.GetByIDWithJoin(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "授权记录不存在")
		}
		return nil, err
	}

	switch userType {
	case constants.UserTypeSuperAdmin, constants.UserTypePlatform:
		// 超级管理员和平台用户: 允许修改任意授权记录备注
	case constants.UserTypeAgent:
		// 代理用户: 只能修改自己创建的授权记录
		if record.AuthorizedBy != userID {
			return nil, errors.New(errors.CodeForbidden, "只能修改自己创建的授权记录备注")
		}
	case constants.UserTypeEnterprise:
		// 企业用户: 禁止修改授权记录备注
		return nil, errors.New(errors.CodeForbidden, "企业用户不允许修改授权记录备注")
	default:
		return nil, errors.New(errors.CodeForbidden, "无权限修改授权记录备注")
	}

	if err := s.authorizationStore.UpdateRemarkWithConstraint(ctx, id, remark, record.AuthorizedBy); err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "授权记录不存在")
		}
		return nil, err
	}

	return s.GetRecordDetail(ctx, id)
}

func parseDate(dateStr string) (time.Time, error) {
	return time.ParseInLocation("2006-01-02", dateStr, time.Local)
}
