package orm

import (
	"context"
	"fmt"
	"github.com/stretchr/testify/assert"
	"strings"
	"testing"
	"time"

	"github.com/go-loremipsum/loremipsum"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo"
	"go.mongodb.org/mongo-driver/v2/mongo/options"
)

type chapter struct {
	ID            bson.ObjectID `bson:"_id" json:"_id"`
	Title         string        `bson:"chapterTitle" json:"chapterTitle" form:"chapterTitle"`
	ChapterID     int           `bson:"id" json:"chapterID" autoinc:"chapters"`
	Index         int           `bson:"index" json:"index" form:"index"`
	Words         int           `bson:"words" json:"words"`
	Notes         string        `bson:"notes" json:"notes" form:"notes"`
	Genre         []string      `bson:"genre" json:"genre" form:"genre"`
	Bands         []band        `json:"bands" bson:"bands" ref:"band,bands"`
	Characters    []string      `bson:"characters" json:"characters" form:"characters"`
	Relationships [][]string    `bson:"relationships" json:"relationships" form:"relationships"`
	Adult         bool          `bson:"adult" json:"adult" form:"adult"`
	Summary       string        `bson:"summary" json:"summary" form:"summary"`
	Hidden        bool          `bson:"hidden" json:"hidden" form:"hidden"`
	LoggedInOnly  bool          `bson:"loggedInOnly" json:"loggedInOnly" form:"loggedInOnly"`
	Posted        time.Time     `bson:"datePosted,omitempty" json:"datePosted"`
	FileName      string        `json:"fileName" bson:"-"`
	Text          string        `json:"text" bson:"-" gridfs:"story_text,/stories/{{.ChapterID}}.txt"`
}

type band struct {
	ID         int64 `bson:"_id" json:"_id"`
	Document   `bson:",inline" json:",inline" coll:"bands"`
	Name       string   `bson:"name" json:"name" form:"name"`
	Locked     bool     `bson:"locked" json:"locked" form:"locked"`
	Characters []string `bson:"characters" json:"characters" form:"characters"`
}
type user struct {
	ID       int64 `bson:"_id" json:"_id"`
	Document `bson:",inline" json:",inline" coll:"users"`
	Username string `bson:"username" json:"username"`
}
type story struct {
	ID        int64 `bson:"_id" json:"_id"`
	Document  `bson:",inline" json:",inline" coll:"stories"`
	Title     string    `bson:"title" json:"title" form:"title"`
	Author    *user     `bson:"author" json:"author" ref:"user"`
	CoAuthor  *user     `bson:"coAuthor" json:"coAuthor" ref:"user"`
	Chapters  []chapter `bson:"chapters" json:"chapters"`
	Recs      int       `bson:"recs" json:"recs"`
	Favs      int       `bson:"favs" json:"favs"`
	Views     int       `bson:"views" json:"views"`
	Completed bool      `bson:"completed" json:"completed" form:"completed"`
	Downloads int       `bson:"downloads" json:"downloads"`
}
type somethingWithNestedChapters struct {
	ID         int64 `bson:"_id" json:"_id"`
	Document   `bson:",inline" json:",inline" coll:"nested_stuff"`
	Chapters   []chapter `bson:"chapters" json:"chapters"`
	NestedText string    `json:"text" bson:"-" gridfs:"nested_text,/nested/{{.ID}}.txt"`
}

func (s *somethingWithNestedChapters) Id() any {
	return s.ID
}

func (s *somethingWithNestedChapters) SetId(id any) {
	s.ID = id.(int64)
}

func (s *story) Id() any {
	return s.ID
}

func (s *band) Id() any {
	return s.ID
}
func (s *user) Id() any {
	return s.ID
}

func (s *story) SetId(id any) {
	s.ID = id.(int64)
	//var t IDocument =s
}

func (s *band) SetId(id any) {
	s.ID = id.(int64)
}

func (s *user) SetId(id any) {
	s.ID = id.(int64)
}

var author = user{
	Username: "tablet.exe",
}

func genChaps(single bool) []chapter {
	var ret []chapter
	var ceil int
	if single {
		ceil = 1
	} else {
		ceil = 5
	}
	emptyRel := make([][]string, 0)
	emptyRel = append(emptyRel, make([]string, 0))
	relMap := [][][]string{
		{
			{"Sean Harris", "Brian Tatler"},
		},
		{
			{"Sean Harris", "Brian Tatler"},
			{"Duncan Scott", "Colin Kimberley"},
		},
		{
			{"Duncan Scott", "Colin Kimberley"},
		},
		emptyRel,
		{
			{"Sean Harris", "Colin Kimberley", "Brian Tatler"},
		},
	}
	l := loremipsum.New()

	for i := 0; i < ceil; i++ {
		spf := fmt.Sprintf("%d.md", i+1)
		ret = append(ret, chapter{
			ID:            bson.NewObjectID(),
			Title:         fmt.Sprintf("-%d-", i+1),
			Index:         i + 1,
			Words:         50,
			Notes:         "notenotenote !!!",
			Genre:         []string{"Slash"},
			Bands:         []band{diamondHead},
			Characters:    []string{"Sean Harris", "Brian Tatler", "Duncan Scott", "Colin Kimberley"},
			Relationships: relMap[i],
			Adult:         true,
			Summary:       l.Paragraph(),
			Hidden:        false,
			LoggedInOnly:  true,
			FileName:      spf,
			Text:          strings.Join(l.ParagraphList(10), "\n\n"),
		})
	}

	return ret
}

func doSomethingWithNested() somethingWithNestedChapters {
	l := loremipsum.New()
	swnc := somethingWithNestedChapters{
		Chapters:   genChaps(false),
		NestedText: strings.Join(l.ParagraphList(15), "\n\n"),
	}
	return swnc
}
func iti_single() story {
	return story{
		Title:     "title",
		Completed: true,
		Chapters:  genChaps(true),
	}
}

func iti_multi() story {
	return story{
		Title:     "Brian Tatler Fucked and Abused Sean Harris",
		Completed: false,
		Chapters:  genChaps(false),
	}
}

func iti_blank() story {
	t := iti_single()
	t.Chapters = make([]chapter, 0)
	return t
}

func initTest() {
	uri := "mongodb://127.0.0.1:27017"
	db := "rockfic_ormTest"
	ic, _ := mongo.Connect(options.Client().ApplyURI(uri))
	ic.Database(db).Drop(context.TODO())
	colls, _ := ic.Database(db).ListCollectionNames(context.TODO(), bson.M{})
	if len(colls) < 1 {
		mdb := ic.Database(db)
		mdb.CreateCollection(context.TODO(), "bands")
		mdb.CreateCollection(context.TODO(), "stories")
		mdb.CreateCollection(context.TODO(), "users")
	}
	defer ic.Disconnect(context.TODO())
	Connect(uri, db)
	author.ID = 696969
	ModelRegistry.Model(band{}, user{}, story{})
}

var metallica = band{
	ID:   1,
	Name: "Metallica",
	Characters: []string{
		"James Hetfield",
		"Lars Ulrich",
		"Kirk Hammett",
		"Cliff Burton",
	},
	Locked: false,
}

var diamondHead = band{
	ID:     503,
	Name:   "Diamond Head",
	Locked: false,
	Characters: []string{
		"Brian Tatler",
		"Sean Harris",
		"Duncan Scott",
		"Colin Kimberley",
	},
}
var bodom = band{
	ID:     74,
	Name:   "Children of Bodom",
	Locked: false,
	Characters: []string{
		"Janne Wirman",
		"Alexi Laiho",
		"Jaska Raatikainen",
		"Henkka T. Blacksmith",
		"Roope Latvala",
		"Daniel Freyberg",
		"Alexander Kuoppala",
	},
}

func saveDoc(t *testing.T, doc IDocument) {
	err := doc.Save()
	assert.Nil(t, err)
}

func createAndSave(t *testing.T, doc IDocument) {
	mdl := Create(doc).(IDocument)
	saveDoc(t, mdl)
}