package kinds

import (
	"net/url"
	"strings"
	"time"
	"mimicry/shared"
	"mimicry/style"
	"mimicry/request"
	"fmt"
)

type Post map[string]any

// TODO: make the Post references *Post because why not

func (p Post) Kind() (string, error) {
	kind, err := shared.Get[string](p, "type")
	return strings.ToLower(kind), err
}

func (p Post) Title() (string, error) {
	title, err := shared.GetNatural(p, "name", "en")
	return strings.TrimSpace(title), err
}

func (p Post) Body() (string, error) {
	body, err := shared.GetNatural(p, "content", "en")
	return strings.TrimSpace(body), err
}

func (p Post) BodyPreview() (string, error) {
	body, err := p.Body()
	return fmt.Sprintf("%s…", string([]rune(body)[:280])), err
}

func (p Post) Identifier() (*url.URL, error) {
	return shared.GetURL(p, "id")
}

func (p Post) Created() (time.Time, error) {
	return shared.GetTime(p, "published")
}

func (p Post) Updated() (time.Time, error) {
	return shared.GetTime(p, "updated")
}

func (p Post) Category() string {
	return "post"
}

func (p Post) Creators() []Actor {
	// TODO: this line needs an existence check
	attributedTo, ok := p["attributedTo"]
	if !ok {
		return []Actor{}
	}

	// if not an array, make it an array
	attributions := []any{}
	if attributedToList, isList := attributedTo.([]any); isList {
		attributions = attributedToList
	} else {
		attributions = []any{attributedTo}
	}

	output := []Actor{}

	for _, el := range attributions {
		switch narrowed := el.(type) {
		case shared.JSON:
			source, err := p.Identifier()
			if err != nil { continue }
			resolved, err := Create(narrowed, source)
			if err != nil { continue }
			actor, isActor := resolved.(Actor)
			if !isActor { continue }
			output = append(output, actor)
		case string:
			url, err := url.Parse(narrowed)
			if err != nil { continue }
			response, err := request.Fetch(url)
			if err != nil { continue }
			// this step will be implicit after merge
			structured, err := Create(response, url)
			if err != nil { continue }
			actor, isActor := structured.(Actor)
			if !isActor { continue }
			output = append(output, actor)
		default: continue
		}
	}

	return output
}

func (p Post) String() string {
	output := ""

	if title, err := p.Title(); err == nil {
		output += style.Bold(title)
		output += "\n"
	}


	if body, err := p.BodyPreview(); err == nil {
		output += body
		output += "\n"
	}

	if created, err := p.Created(); err == nil {
		output += time.Now().Sub(created).String()
	}

	if creators := p.Creators(); len(creators) != 0 {
		output += " "
		for _, creator := range creators {
			if name, err := creator.InlineName(); err == nil {
				output += style.Bold(name) + ", "
			}
		}
	}

	return strings.TrimSpace(output)
}