package models

import (
	"context"
	"time"
)

type Studio struct {
	ID        int       `json:"id"`
	Name      string    `json:"name"`
	ParentID  *int      `json:"parent_id"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	// Rating expressed in 1-100 scale
	Rating        *int   `json:"rating"`
	Favorite      bool   `json:"favorite"`
	Details       string `json:"details"`
	IgnoreAutoTag bool   `json:"ignore_auto_tag"`
	Organized     bool   `json:"organized"`

	Aliases  RelatedStrings  `json:"aliases"`
	URLs     RelatedStrings  `json:"urls"`
	TagIDs   RelatedIDs      `json:"tag_ids"`
	StashIDs RelatedStashIDs `json:"stash_ids"`
}

type CreateStudioInput struct {
	*Studio

	CustomFields map[string]interface{} `json:"custom_fields"`
}

type UpdateStudioInput struct {
	*Studio

	CustomFields CustomFieldsInput `json:"custom_fields"`
}

func NewStudio() Studio {
	currentTime := time.Now()
	return Studio{
		CreatedAt: currentTime,
		UpdatedAt: currentTime,
	}
}

func NewCreateStudioInput() CreateStudioInput {
	s := NewStudio()
	return CreateStudioInput{
		Studio: &s,
	}
}

// StudioPartial represents part of a Studio object. It is used to update the database entry.
type StudioPartial struct {
	ID       int
	Name     OptionalString
	ParentID OptionalInt
	// Rating expressed in 1-100 scale
	Rating        OptionalInt
	Favorite      OptionalBool
	Details       OptionalString
	CreatedAt     OptionalTime
	UpdatedAt     OptionalTime
	IgnoreAutoTag OptionalBool
	Organized     OptionalBool

	Aliases  *UpdateStrings
	URLs     *UpdateStrings
	TagIDs   *UpdateIDs
	StashIDs *UpdateStashIDs

	CustomFields CustomFieldsInput
}

func NewStudioPartial() StudioPartial {
	currentTime := time.Now()
	return StudioPartial{
		UpdatedAt: NewOptionalTime(currentTime),
	}
}

func (s *Studio) LoadAliases(ctx context.Context, l AliasLoader) error {
	return s.Aliases.load(func() ([]string, error) {
		return l.GetAliases(ctx, s.ID)
	})
}

func (s *Studio) LoadURLs(ctx context.Context, l URLLoader) error {
	return s.URLs.load(func() ([]string, error) {
		return l.GetURLs(ctx, s.ID)
	})
}

func (s *Studio) LoadTagIDs(ctx context.Context, l TagIDLoader) error {
	return s.TagIDs.load(func() ([]int, error) {
		return l.GetTagIDs(ctx, s.ID)
	})
}

func (s *Studio) LoadStashIDs(ctx context.Context, l StashIDLoader) error {
	return s.StashIDs.load(func() ([]StashID, error) {
		return l.GetStashIDs(ctx, s.ID)
	})
}

func (s *Studio) LoadRelationships(ctx context.Context, l PerformerReader) error {
	if err := s.LoadAliases(ctx, l); err != nil {
		return err
	}

	if err := s.LoadTagIDs(ctx, l); err != nil {
		return err
	}

	if err := s.LoadStashIDs(ctx, l); err != nil {
		return err
	}

	return nil
}
