package payment

import (
	"context"
	"errors"
)

var (
	ErrDependencyUnavailable = errors.New("dependency unavailable")
	ErrPaymentUnavailable    = errors.New("payment unavailable")
	ErrPaymentCannotStart    = errors.New("payment cannot start")
	ErrPaymentVerifyFailed   = errors.New("payment verify failed")
	ErrPaymentNotFound       = errors.New("payment not found")
	ErrRefundCannotStart     = errors.New("refund cannot start")
)

type Service struct {
	repo *Repository
}

func NewService(repo *Repository) *Service {
	return &Service{repo: repo}
}

func (s *Service) Start(ctx context.Context, userID uint64, orderID uint64, req StartPaymentRequest, clientIP string) (*PaymentDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if userID == 0 || orderID == 0 {
		return nil, ErrPaymentCannotStart
	}
	return s.repo.Start(ctx, userID, orderID, req, clientIP)
}

func (s *Service) Query(ctx context.Context, userID uint64, orderID uint64) (*PaymentDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if userID == 0 || orderID == 0 {
		return nil, ErrPaymentNotFound
	}
	return s.repo.Query(ctx, userID, orderID)
}

func (s *Service) HandleLeshuaNotify(ctx context.Context, params map[string]string, rawPayload string, contentType string) (*NotifyResult, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	return s.repo.HandleLeshuaNotify(ctx, params, rawPayload, contentType)
}

func (s *Service) HandleNotify(ctx context.Context, provider string, params map[string]string, rawPayload string, contentType string, authorization string) (*NotifyResult, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	return s.repo.HandleNotify(ctx, provider, params, rawPayload, contentType, authorization)
}

func (s *Service) StartRefund(ctx context.Context, orderID uint64, refundAmountCent int64, bizType string, remark string) (*RefundDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if orderID == 0 || refundAmountCent <= 0 {
		return nil, ErrRefundCannotStart
	}
	return s.repo.StartRefund(ctx, orderID, refundAmountCent, bizType, remark)
}

func (s *Service) QueryRefundStatus(ctx context.Context, orderID uint64) (*RefundDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if orderID == 0 {
		return nil, ErrPaymentNotFound
	}
	return s.repo.QueryRefundStatus(ctx, orderID)
}

func (s *Service) AdminList(ctx context.Context, query AdminPaymentQuery) (*PaginatedResult, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if query.Page < 1 {
		query.Page = 1
	}
	if query.PageSize < 1 {
		query.PageSize = 20
	}
	if query.PageSize > 100 {
		query.PageSize = 100
	}
	return s.repo.AdminList(ctx, query)
}
