package models

import (
	"fmt"
	"strings"
	"time"

	"github.com/bluesky-social/indigo/atproto/syntax"
	securejoin "github.com/cyphar/filepath-securejoin"
	"tangled.org/core/api/tangled"
)

type Repo struct {
	Id          int64
	Did         string
	Name        string
	Knot        string
	Rkey        string
	Created     time.Time
	Description string
	Website     string
	Topics      []string
	Spindle     string
	Labels      []string
	RepoDid     string

	// optionally, populate this when querying for reverse mappings
	RepoStats *RepoStats

	// optional
	Source string
}

func (r *Repo) AsRecord() tangled.Repo {
	var source, spindle, description, website *string

	if r.Source != "" {
		source = &r.Source
	}

	if r.Spindle != "" {
		spindle = &r.Spindle
	}

	if r.Description != "" {
		description = &r.Description
	}

	if r.Website != "" {
		website = &r.Website
	}

	var repoDid *string
	if r.RepoDid != "" {
		repoDid = &r.RepoDid
	}

	return tangled.Repo{
		Knot:        r.Knot,
		Name:        r.Name,
		Description: description,
		Website:     website,
		Topics:      r.Topics,
		CreatedAt:   r.Created.Format(time.RFC3339),
		Source:      source,
		Spindle:     spindle,
		Labels:      r.Labels,
		RepoDid:     repoDid,
	}
}

func (r Repo) RepoAt() syntax.ATURI {
	return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", r.Did, tangled.RepoNSID, r.Rkey))
}

func (r Repo) RepoIdentifier() string {
	if r.RepoDid != "" {
		return r.RepoDid
	}
	p, _ := securejoin.SecureJoin(r.Did, r.Name)
	return p
}

func (r Repo) TopicStr() string {
	return strings.Join(r.Topics, " ")
}

type RepoStats struct {
	Language   string
	StarCount  int
	IssueCount IssueCount
	PullCount  PullCount
}

type IssueCount struct {
	Open   int
	Closed int
}

type PullCount struct {
	Open    int
	Merged  int
	Closed  int
	Deleted int
}

type RepoLabel struct {
	Id      int64
	RepoAt  syntax.ATURI
	LabelAt syntax.ATURI
}

type RepoGroup struct {
	Repo   *Repo
	Issues []Issue
}

type BlobContentType int

const (
	BlobContentTypeCode BlobContentType = iota
	BlobContentTypeMarkup
	BlobContentTypeImage
	BlobContentTypeSvg
	BlobContentTypeVideo
	BlobContentTypeSubmodule
)

func (ty BlobContentType) IsCode() bool      { return ty == BlobContentTypeCode }
func (ty BlobContentType) IsMarkup() bool    { return ty == BlobContentTypeMarkup }
func (ty BlobContentType) IsImage() bool     { return ty == BlobContentTypeImage }
func (ty BlobContentType) IsSvg() bool       { return ty == BlobContentTypeSvg }
func (ty BlobContentType) IsVideo() bool     { return ty == BlobContentTypeVideo }
func (ty BlobContentType) IsSubmodule() bool { return ty == BlobContentTypeSubmodule }

type BlobView struct {
	HasTextView     bool // can show as code/text
	HasRenderedView bool // can show rendered (markup/image/video/submodule)
	HasRawView      bool // can download raw (everything except submodule)

	// current display mode
	ShowingRendered bool // currently in rendered mode

	// content type flags
	ContentType BlobContentType

	// Content data
	Contents   string
	ContentSrc string // URL for media files
	Lines      int
	SizeHint   uint64
}

// if both views are available, then show a toggle between them
func (b BlobView) ShowToggle() bool {
	return b.HasTextView && b.HasRenderedView
}

func (b BlobView) IsUnsupported() bool {
	// no view available, only raw
	return !(b.HasRenderedView || b.HasTextView)
}

func (b BlobView) ShowingText() bool {
	return !b.ShowingRendered
}
