package order

import "errors"

var (
	ErrDependencyUnavailable  = errors.New("dependency unavailable")
	ErrInvalidRentHours       = errors.New("invalid rent hours")
	ErrListingUnavailable     = errors.New("listing unavailable")
	ErrCannotRentOwnListing   = errors.New("cannot rent own listing")
	ErrInsufficientBalance    = errors.New("insufficient balance")
	ErrOrderCannotPay         = errors.New("order cannot pay")
	ErrChannelPaymentRequired = errors.New("channel payment required")
	ErrOrderCannotCancel      = errors.New("order cannot cancel")
	ErrOrderCannotHandoff     = errors.New("order cannot handoff")
	ErrOrderCannotReceive     = errors.New("order cannot receive")
	ErrOrderCannotReturn      = errors.New("order cannot return")
	ErrOrderCannotComplete    = errors.New("order cannot complete")
	ErrCheckoutCannotSubmit   = errors.New("checkout cannot submit")
	ErrCheckoutCannotConfirm  = errors.New("checkout cannot confirm")
	ErrCheckoutCannotCounter  = errors.New("checkout cannot counter")
	ErrInvalidCheckoutAmount  = errors.New("invalid checkout amount")
	ErrPermissionDenied       = errors.New("permission denied")
)

const internalOrderHours = 24

type Service struct {
	repo *Repository
}

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

func (s *Service) Create(userID uint64, req CreateRequest) (*OrderDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if req.ListingID == 0 {
		return nil, ErrInvalidRentHours
	}
	return s.repo.Create(userID, req)
}

func (s *Service) Cancel(userID uint64, orderID uint64) error {
	if s.repo == nil {
		return ErrDependencyUnavailable
	}
	return s.repo.Cancel(userID, orderID)
}

func (s *Service) Pay(userID uint64, orderID uint64) error {
	if s.repo == nil {
		return ErrDependencyUnavailable
	}
	if orderID == 0 {
		return ErrOrderCannotPay
	}
	return s.repo.Pay(userID, orderID)
}

func (s *Service) SubmitHandoff(userID uint64, orderID uint64, req SubmitHandoffRequest) (*HandoffRecordDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if orderID == 0 || req.Content == "" {
		return nil, ErrOrderCannotHandoff
	}
	return s.repo.SubmitHandoff(userID, orderID, req)
}

func (s *Service) ConfirmReceive(userID uint64, orderID uint64) error {
	if s.repo == nil {
		return ErrDependencyUnavailable
	}
	return s.repo.ConfirmReceive(userID, orderID)
}

func (s *Service) HandoffRecords(userID uint64, orderID uint64) ([]HandoffRecordDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	return s.repo.HandoffRecords(userID, orderID)
}

func (s *Service) SubmitReturn(userID uint64, orderID uint64, req SubmitReturnRequest) (*HandoffRecordDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if orderID == 0 || req.Content == "" {
		return nil, ErrOrderCannotReturn
	}
	return s.repo.SubmitReturn(userID, orderID, req)
}

func (s *Service) SubmitCheckout(userID uint64, orderID uint64, req SubmitCheckoutRequest) (*HandoffRecordDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if orderID == 0 || req.Content == "" {
		return nil, ErrCheckoutCannotSubmit
	}
	return s.repo.SubmitCheckout(userID, orderID, req)
}

func (s *Service) ConfirmReturn(userID uint64, orderID uint64) error {
	if s.repo == nil {
		return ErrDependencyUnavailable
	}
	return s.repo.ConfirmReturn(userID, orderID)
}

func (s *Service) ConfirmCheckout(userID uint64, orderID uint64) error {
	if s.repo == nil {
		return ErrDependencyUnavailable
	}
	return s.repo.ConfirmCheckout(userID, orderID)
}

func (s *Service) CounterCheckout(userID uint64, orderID uint64, req CounterCheckoutRequest) (*CheckoutDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if orderID == 0 || req.Reason == "" {
		return nil, ErrCheckoutCannotCounter
	}
	return s.repo.CounterCheckout(userID, orderID, req)
}

func (s *Service) AcceptCheckout(userID uint64, orderID uint64) error {
	if s.repo == nil {
		return ErrDependencyUnavailable
	}
	return s.repo.AcceptCheckout(userID, orderID)
}

func (s *Service) ListForUser(userID uint64) ([]OrderDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	return s.repo.ListForUser(userID)
}

func (s *Service) ListAdmin() ([]OrderDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	return s.repo.ListAdmin()
}

func (s *Service) FindAdmin(orderID uint64) (*OrderDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	return s.repo.FindAdmin(orderID)
}

func (s *Service) HandoffRecordsAdmin(orderID uint64) ([]HandoffRecordDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	return s.repo.HandoffRecordsAdmin(orderID)
}

func (s *Service) AdminClose(adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
	if s.repo == nil {
		return ErrDependencyUnavailable
	}
	if orderID == 0 || req.Reason == "" {
		return ErrOrderCannotComplete
	}
	return s.repo.AdminClose(adminID, orderID, req, meta)
}

func (s *Service) AdminMarkAbnormal(adminID uint64, orderID uint64, req AdminActionRequest, meta AuditMeta) error {
	if s.repo == nil {
		return ErrDependencyUnavailable
	}
	if orderID == 0 || req.Reason == "" {
		return ErrOrderCannotComplete
	}
	return s.repo.AdminMarkAbnormal(adminID, orderID, req, meta)
}

func (s *Service) AdminRefund(orderID uint64) (*RefundStatusDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if orderID == 0 {
		return nil, ErrOrderCannotComplete
	}
	return s.repo.AdminRefund(orderID)
}

func (s *Service) AdminRefundStatus(orderID uint64) (*RefundStatusDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if orderID == 0 {
		return nil, ErrOrderCannotComplete
	}
	return s.repo.AdminRefundStatus(orderID)
}

func (s *Service) FindForUser(userID uint64, orderID uint64) (*OrderDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	return s.repo.FindForUser(userID, orderID)
}
