package service

import (
	"context"
	"errors"

	"wucher/internal/domain/medicine"
	"wucher/internal/shared/pkg/sortkey"
)

type MedicineService struct {
	repo medicine.Repository
}

func NewMedicineService(repo medicine.Repository) *MedicineService {
	return &MedicineService{repo: repo}
}

func (s *MedicineService) Create(ctx context.Context, row *medicine.Medicine) error {
	return s.repo.Create(ctx, row)
}

func (s *MedicineService) Update(ctx context.Context, row *medicine.Medicine) error {
	return s.repo.Update(ctx, row)
}

func (s *MedicineService) Delete(ctx context.Context, id []byte, deletedBy []byte) error {
	return s.repo.Delete(ctx, id, deletedBy)
}

func (s *MedicineService) GetByID(ctx context.Context, id []byte) (*medicine.Medicine, error) {
	return s.repo.GetByID(ctx, id)
}

func (s *MedicineService) List(ctx context.Context, filter, sort string, limit, offset int) ([]medicine.Medicine, int64, error) {
	return s.repo.List(ctx, filter, normalizeMedicineSort(sort), limit, offset)
}

func normalizeMedicineSort(sort string) string {
	return normalizeSortByRules(sort,
		sortExpr(
			joinSortClauses(sortkey.ActivePositiveSortClauses("", "is_active", "sortkey", "name", false)),
			joinSortClauses(sortkey.ActivePositiveSortClauses("", "is_active", "sortkey", "name", true)),
			"sortkey",
		),
		sortField("name"),
		sortExpr(
			"COALESCE(NULLIF(note, ''), pack) ASC",
			"COALESCE(NULLIF(note, ''), pack) DESC",
			"note",
		),
		sortField("pack"),
		sortField("unit"),
		sortField("`column`", "column"),
		sortField("is_active"),
		sortField("created_at"),
		sortField("updated_at"),
	)
}

func (s *MedicineService) CreateGroup(ctx context.Context, row *medicine.MedicineGroup) error {
	repo, ok := s.repo.(interface {
		CreateGroup(context.Context, *medicine.MedicineGroup) error
	})
	if !ok {
		return errors.New("medicine group repository not configured")
	}
	return repo.CreateGroup(ctx, row)
}

func (s *MedicineService) UpdateGroup(ctx context.Context, row *medicine.MedicineGroup) error {
	repo, ok := s.repo.(interface {
		UpdateGroup(context.Context, *medicine.MedicineGroup) error
	})
	if !ok {
		return errors.New("medicine group repository not configured")
	}
	return repo.UpdateGroup(ctx, row)
}

func (s *MedicineService) DeleteGroup(ctx context.Context, id []byte, deletedBy []byte) error {
	repo, ok := s.repo.(interface {
		DeleteGroup(context.Context, []byte, []byte) error
	})
	if !ok {
		return errors.New("medicine group repository not configured")
	}
	return repo.DeleteGroup(ctx, id, deletedBy)
}

func (s *MedicineService) GetGroupByID(ctx context.Context, id []byte) (*medicine.MedicineGroup, error) {
	repo, ok := s.repo.(interface {
		GetGroupByID(context.Context, []byte) (*medicine.MedicineGroup, error)
	})
	if !ok {
		return nil, errors.New("medicine group repository not configured")
	}
	return repo.GetGroupByID(ctx, id)
}

func (s *MedicineService) ListGroups(ctx context.Context, filter, sort string, limit, offset int) ([]medicine.MedicineGroup, int64, error) {
	repo, ok := s.repo.(interface {
		ListGroups(context.Context, string, string, int, int) ([]medicine.MedicineGroup, int64, error)
	})
	if !ok {
		return nil, 0, errors.New("medicine group repository not configured")
	}
	return repo.ListGroups(ctx, filter, normalizeMedicineGroupSort(sort), limit, offset)
}

func normalizeMedicineGroupSort(sort string) string {
	return normalizeSortByRules(sort,
		sortField("name"),
		sortField("created_at"),
		sortField("updated_at"),
	)
}

func (s *MedicineService) CreateReaction(ctx context.Context, row *medicine.MotorReaction) error {
	repo, ok := s.repo.(interface {
		CreateReaction(context.Context, *medicine.MotorReaction) error
	})
	if !ok {
		return errors.New("motor reaction repository not configured")
	}
	return repo.CreateReaction(ctx, row)
}

func (s *MedicineService) UpdateReaction(ctx context.Context, row *medicine.MotorReaction) error {
	repo, ok := s.repo.(interface {
		UpdateReaction(context.Context, *medicine.MotorReaction) error
	})
	if !ok {
		return errors.New("motor reaction repository not configured")
	}
	return repo.UpdateReaction(ctx, row)
}

func (s *MedicineService) DeleteReaction(ctx context.Context, id []byte, deletedBy []byte) error {
	repo, ok := s.repo.(interface {
		DeleteReaction(context.Context, []byte, []byte) error
	})
	if !ok {
		return errors.New("motor reaction repository not configured")
	}
	return repo.DeleteReaction(ctx, id, deletedBy)
}

func (s *MedicineService) GetReactionByID(ctx context.Context, id []byte) (*medicine.MotorReaction, error) {
	repo, ok := s.repo.(interface {
		GetReactionByID(context.Context, []byte) (*medicine.MotorReaction, error)
	})
	if !ok {
		return nil, errors.New("motor reaction repository not configured")
	}
	return repo.GetReactionByID(ctx, id)
}

func (s *MedicineService) ListReactions(ctx context.Context, filter, sort string, limit, offset int) ([]medicine.MotorReaction, int64, error) {
	repo, ok := s.repo.(interface {
		ListReactions(context.Context, string, string, int, int) ([]medicine.MotorReaction, int64, error)
	})
	if !ok {
		return nil, 0, errors.New("motor reaction repository not configured")
	}
	return repo.ListReactions(ctx, filter, normalizeMotorReactionSort(sort), limit, offset)
}

func normalizeMotorReactionSort(sort string) string {
	return normalizeSortByRules(sort,
		sortField("name"),
		sortField("score"),
		sortField("created_at"),
		sortField("updated_at"),
	)
}
