// Copyright F3 Authors
// SPDX-License-Identifier: MIT

package f3

import (
	"encoding/json"
	"strings"

	"code.forgejo.org/f3/gof3/v3/util"
)

type Interface interface {
	GetID() string
	GetName() string
	HasName() bool
	SetName(string)
	SetID(id string)
	IsNil() bool
	GetReferences() References
	ToReference() *Reference
	IsUpToDate(Interface) bool
	Clone() Interface
}

type ReferenceInterface interface {
	Get() string
	Set(reference string)
	GetIDAsString() string
	GetIDAsInt() int64
}

type Reference struct {
	ID string
}

func (r *Reference) Get() string {
	return r.ID
}

func (r *Reference) Set(reference string) {
	r.ID = reference
}

func (r *Reference) GetIDAsInt() int64 {
	return util.ParseInt(r.GetIDAsString())
}

func (r *Reference) GetIDAsString() string {
	s := strings.Split(r.ID, "/")
	return s[len(s)-1]
}

type References []ReferenceInterface

func (r *Reference) UnmarshalJSON(b []byte) error {
	return json.Unmarshal(b, &r.ID)
}

func (r Reference) MarshalJSON() ([]byte, error) {
	return json.Marshal(r.ID)
}

func (r *Reference) GetID() string             { return r.ID }
func (r *Reference) SetID(id string)           { r.ID = id }
func (r *Reference) IsNil() bool               { return r == nil || r.ID == "0" || r.ID == "" }
func (r Reference) Equal(other Reference) bool { return r.ID == other.ID }

func NewReferences() References {
	return make([]ReferenceInterface, 0, 1)
}

func NewReference(id string) *Reference {
	r := &Reference{}
	r.SetID(id)
	return r
}

type Common struct {
	Index Reference `json:"index"`
}

func (c *Common) GetID() string             { return c.Index.GetID() }
func (c *Common) GetName() string           { return c.GetID() }
func (c *Common) HasName() bool             { return false }
func (c *Common) SetName(string)            {}
func (c *Common) SetID(id string)           { c.Index.SetID(id) }
func (c *Common) IsNil() bool               { return c == nil || c.Index.IsNil() }
func (c *Common) GetReferences() References { return NewReferences() }
func (c *Common) ToReference() *Reference   { return &c.Index }
func (c Common) Equal(other Common) bool    { return true }
func (c Common) IsUpToDate(Interface) bool  { return false }

var Nil = &Common{}

func NewCommon(id string) Common {
	return Common{Index: *NewReference(id)}
}

func (c *Common) Clone() Interface {
	clone := &Common{}
	*clone = *c
	return clone
}
