package analytic

import (
	"context"
	"errors"
	"fmt"
	"time"

	"git.gocasts.ir/ebhomengo/niki/patientapp/service/entity"
)

var (
	ErrInvalidProvinceID = errors.New("invalid province id")
	ErrInvalidCountryID  = errors.New("invalid country id")
	ErrInvalidMapLevel   = errors.New("invalid map level")
)

type Repository interface {
	GetPatients(ctx context.Context, f PatientFilter) ([]entity.UserMeta, error)
	CountPatients(ctx context.Context, f PatientFilter) (int, error)

	SummaryByCity(ctx context.Context, provinceID uint, f PatientMapFilter) (map[uint][]entity.MapSummaryItem, error)
	SummaryByProvince(ctx context.Context, f PatientMapFilter) (map[uint][]entity.MapSummaryItem, error)
}

type Service struct {
	repository Repository
}

func NewPatientAnalyticService(repo Repository) Service {
	return Service{
		repository: repo,
	}
}

func (s Service) List(ctx context.Context, req ListPatientAnalyticRequest) (PatientAnalyticResponse, error) {

	limit, offset := normalizeLimitOffset(req.Pagination.Limit, req.Pagination.Offset)

	// convert age range
	dobFrom, dobTo := ageRangeToDOB(req.MinAge, req.MaxAge, time.Now())

	filter := PatientFilter{
		DOBFrom:      dobFrom,
		DOBTo:        dobTo,
		Sex:          req.Sex,
		AddressCity:  *req.City,
		AddressState: *req.Province,
		Search:       req.Search,
		Limit:        limit,
		Offset:       offset,
	}

	items, err := s.repository.GetPatients(ctx, filter)
	if err != nil {
		return PatientAnalyticResponse{}, fmt.Errorf("GetPatients: %w", err)
	}

	total, err := s.repository.CountPatients(ctx, filter)
	if err != nil {
		return PatientAnalyticResponse{}, fmt.Errorf("CountPatients: %w", err)
	}

	// mapping response
	out := make([]PatientAnalyticItem, 0, len(items))
	for _, value := range items {
		out = append(out, ToPatientResponse(value))
	}

	return PatientAnalyticResponse{
		Items: out,
		Pagination: &Pagination{
			Limit:  limit,
			Offset: offset,
		},
		Total: total,
	}, nil

}

func (s Service) GetMapSummary(ctx context.Context, req GetPatientMapSummaryRequest) (GetPatientMapSummaryResponse, error) {

	dobFrom, dobTo := ageRangeToDOB(req.MinAge, req.MaxAge, time.Now())

	filter := PatientMapFilter{
		MinDOB: dobFrom,
		MaxDOB: dobTo,
		Sex:    req.Sex,
		Search: req.Search,
	}

	switch req.Level {
	case entity.MapLevelCity:
		if req.ParentID == nil || *req.ParentID <= 0 {
			return GetPatientMapSummaryResponse{}, ErrInvalidProvinceID
		}

		items, err := s.repository.SummaryByCity(ctx, uint(*req.ParentID), filter)
		if err != nil {
			return GetPatientMapSummaryResponse{}, fmt.Errorf("SummaryByCity: %w", err)
		}
		return GetPatientMapSummaryResponse{Level: req.Level, Items: items}, nil

	case entity.MapLevelProvince:
		if req.ParentID == nil || *req.ParentID <= 0 {
			return GetPatientMapSummaryResponse{}, ErrInvalidCountryID
		}

		items, err := s.repository.SummaryByProvince(ctx, filter)
		if err != nil {
			return GetPatientMapSummaryResponse{}, fmt.Errorf("SummaryByProvince: %w", err)
		}
		return GetPatientMapSummaryResponse{Level: req.Level, Items: items}, nil

	default:
		return GetPatientMapSummaryResponse{}, ErrInvalidMapLevel
	}

}
