package domain

import (
	"math"
	"net/url"
)

type VillagesSyncedEventPayload struct {
	serverKey            string
	serverURL            *url.URL
	versionCode          string
	numVillages          int
	numPlayerVillages    int
	numBarbarianVillages int
	numBonusVillages     int
}

const villagesSyncedEventPayloadModelName = "VillagesSyncedEventPayload"

func NewVillagesSyncedEventPayload(
	serverKey string,
	serverURL *url.URL,
	versionCode string,
	numVillages int,
	numPlayerVillages int,
	numBarbarianVillages int,
	numBonusVillages int,
) (VillagesSyncedEventPayload, error) {
	if serverKey == "" {
		return VillagesSyncedEventPayload{}, ValidationError{
			Model: villagesSyncedEventPayloadModelName,
			Field: "serverKey",
			Err:   ErrRequired,
		}
	}

	if serverURL == nil {
		return VillagesSyncedEventPayload{}, ValidationError{
			Model: villagesSyncedEventPayloadModelName,
			Field: "serverURL",
			Err:   ErrNil,
		}
	}

	if versionCode == "" {
		return VillagesSyncedEventPayload{}, ValidationError{
			Model: villagesSyncedEventPayloadModelName,
			Field: "versionCode",
			Err:   ErrRequired,
		}
	}

	if err := validateIntInRange(numVillages, 0, math.MaxInt); err != nil {
		return VillagesSyncedEventPayload{}, ValidationError{
			Model: villagesSyncedEventPayloadModelName,
			Field: "numVillages",
			Err:   err,
		}
	}

	if err := validateIntInRange(numPlayerVillages, 0, math.MaxInt); err != nil {
		return VillagesSyncedEventPayload{}, ValidationError{
			Model: villagesSyncedEventPayloadModelName,
			Field: "numPlayerVillages",
			Err:   err,
		}
	}

	if err := validateIntInRange(numBarbarianVillages, 0, math.MaxInt); err != nil {
		return VillagesSyncedEventPayload{}, ValidationError{
			Model: villagesSyncedEventPayloadModelName,
			Field: "numBarbarianVillages",
			Err:   err,
		}
	}

	if err := validateIntInRange(numBonusVillages, 0, math.MaxInt); err != nil {
		return VillagesSyncedEventPayload{}, ValidationError{
			Model: villagesSyncedEventPayloadModelName,
			Field: "numBonusVillages",
			Err:   err,
		}
	}

	return VillagesSyncedEventPayload{
		serverKey:            serverKey,
		serverURL:            serverURL,
		versionCode:          versionCode,
		numVillages:          numVillages,
		numPlayerVillages:    numPlayerVillages,
		numBarbarianVillages: numBarbarianVillages,
		numBonusVillages:     numBonusVillages,
	}, nil
}

func NewVillagesSyncedEventPayloadFromVillages(
	serverKey string,
	serverURL *url.URL,
	versionCode string,
	villages BaseVillages,
) (VillagesSyncedEventPayload, error) {
	numPlayerVillages := 0
	numBarbarianVillages := 0
	numBonusVillages := 0

	for _, v := range villages {
		if v.PlayerID() > 0 {
			numPlayerVillages++
		} else {
			numBarbarianVillages++
		}

		if v.Bonus() > 0 {
			numBonusVillages++
		}
	}

	return NewVillagesSyncedEventPayload(
		serverKey,
		serverURL,
		versionCode,
		len(villages),
		numPlayerVillages,
		numBarbarianVillages,
		numBonusVillages,
	)
}

func (p VillagesSyncedEventPayload) ServerKey() string {
	return p.serverKey
}

func (p VillagesSyncedEventPayload) ServerURL() *url.URL {
	return p.serverURL
}

func (p VillagesSyncedEventPayload) VersionCode() string {
	return p.versionCode
}

func (p VillagesSyncedEventPayload) NumVillages() int {
	return p.numVillages
}

func (p VillagesSyncedEventPayload) NumPlayerVillages() int {
	return p.numPlayerVillages
}

func (p VillagesSyncedEventPayload) NumBarbarianVillages() int {
	return p.numBarbarianVillages
}

func (p VillagesSyncedEventPayload) NumBonusVillages() int {
	return p.numBonusVillages
}
