package bunmodel

import (
	"fmt"
	"time"

	"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
	"github.com/uptrace/bun"
)

type Ennoblement struct {
	bun.BaseModel `bun:"table:ennoblements,alias:ennoblement"`

	ID         int       `bun:"id,pk,autoincrement,identity"`
	ServerKey  string    `bun:"server_key,nullzero"`
	VillageID  int       `bun:"village_id,nullzero"`
	Village    Village   `bun:"village,rel:belongs-to,join:village_id=id,join:server_key=server_key"`
	NewOwnerID int       `bun:"new_owner_id,nullzero"`
	NewOwner   Player    `bun:"new_owner,rel:belongs-to,join:new_owner_id=id,join:server_key=server_key"`
	NewTribeID int       `bun:"new_tribe_id,nullzero"`
	NewTribe   Tribe     `bun:"new_tribe,rel:belongs-to,join:new_tribe_id=id,join:server_key=server_key"`
	OldOwnerID int       `bun:"old_owner_id,nullzero"`
	OldOwner   Player    `bun:"old_owner,rel:belongs-to,join:old_owner_id=id,join:server_key=server_key"`
	OldTribeID int       `bun:"old_tribe_id,nullzero"`
	OldTribe   Tribe     `bun:"old_tribe,rel:belongs-to,join:old_tribe_id=id,join:server_key=server_key"`
	Points     int       `bun:"points"`
	CreatedAt  time.Time `bun:"created_at,nullzero"`
}

func (e Ennoblement) ToDomain() (domain.Ennoblement, error) {
	converted, err := domain.UnmarshalEnnoblementFromDatabase(
		e.ID,
		e.ServerKey,
		e.VillageID,
		e.NewOwnerID,
		e.NewTribeID,
		e.OldOwnerID,
		e.OldTribeID,
		e.Points,
		e.CreatedAt,
	)
	if err != nil {
		return domain.Ennoblement{}, fmt.Errorf(
			"couldn't construct domain.Ennoblement (id=%d,serverKey=%s): %w",
			e.ID,
			e.ServerKey,
			err,
		)
	}

	return converted, nil
}

//nolint:gocyclo
func (e Ennoblement) ToDomainWithRelations() (domain.EnnoblementWithRelations, error) {
	converted, err := e.ToDomain()
	if err != nil {
		return domain.EnnoblementWithRelations{}, err
	}

	// in some cases there is no corresponding village in the db (old ennoblements)
	var village domain.VillageMeta
	if e.Village.ID > 0 {
		village, err = e.Village.ToMeta()
		if err != nil {
			return domain.EnnoblementWithRelations{}, err
		}
	}

	// in some cases there is no corresponding player in the db (old ennoblements)
	var newOwner domain.PlayerMeta
	if e.NewOwner.ID > 0 {
		newOwner, err = e.NewOwner.ToMeta()
		if err != nil {
			return domain.EnnoblementWithRelations{}, err
		}
	}

	var newTribe domain.NullTribeMeta
	if e.NewTribe.ID > 0 {
		newTribe.Valid = true
		newTribe.V, err = e.NewTribe.ToMeta()
		if err != nil {
			return domain.EnnoblementWithRelations{}, err
		}
	}

	var oldOwner domain.NullPlayerMeta
	if e.OldOwner.ID > 0 {
		oldOwner.Valid = true
		oldOwner.V, err = e.OldOwner.ToMeta()
		if err != nil {
			return domain.EnnoblementWithRelations{}, err
		}
	}

	var oldTribe domain.NullTribeMeta
	if e.OldTribe.ID > 0 {
		oldTribe.Valid = true
		oldTribe.V, err = e.OldTribe.ToMeta()
		if err != nil {
			return domain.EnnoblementWithRelations{}, err
		}
	}

	return converted.WithRelations(village, newOwner, newTribe, oldOwner, oldTribe), nil
}

type Ennoblements []Ennoblement

func (es Ennoblements) ToDomain() (domain.Ennoblements, error) {
	return sliceToDomain(es)
}

func (es Ennoblements) ToDomainWithRelations() (domain.EnnoblementsWithRelations, error) {
	return sliceToDomainWithRelations(es)
}
