// Command seed populates a demo environment (§11.11): one demo customer
// (offline ticketing type), 1 admin, 2 consultants, 6 developers, pool
// memberships, and sample conversations. Idempotent: existing users (by
// email) and customers (by name) are reused, not duplicated.
//
//	MONGO_SEED_URI=mongodb://127.0.0.1:27017 go run ./scripts
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"time"

	"go.mongodb.org/mongo-driver/v2/bson"

	"bountyboard/internal/auth"
	"bountyboard/internal/config"
	"bountyboard/internal/domain"
	"bountyboard/internal/store"
	"bountyboard/internal/ulid"

	"go.mongodb.org/mongo-driver/v2/mongo"
	"go.mongodb.org/mongo-driver/v2/mongo/options"
)

const demoPassword = "demo-pass-123"

func main() {
	_ = config.LoadDotEnv(".env")
	uri := os.Getenv("MONGO_SEED_URI")
	if uri == "" {
		uri = "mongodb://127.0.0.1:27017"
	}
	dbName := os.Getenv("MONGO_DB")
	if dbName == "" {
		dbName = "bountyboard"
	}
	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()

	client, err := mongo.Connect(options.Client().ApplyURI(uri).
		SetServerSelectionTimeout(5 * time.Second))
	if err != nil {
		log.Fatalf("connect: %v", err)
	}
	defer client.Disconnect(context.Background())
	st := &store.Store{Client: client, DB: client.Database(dbName)}
	if err := store.EnsureIndexes(ctx, st.DB); err != nil {
		log.Fatalf("indexes: %v", err)
	}

	user := func(email, name string, roles domain.Roles) *domain.User {
		if u, err := st.UserByEmail(ctx, email); err == nil {
			fmt.Printf("  exists: %s\n", email)
			return u
		}
		hash, err := auth.HashPassword(demoPassword)
		if err != nil {
			log.Fatal(err)
		}
		u := &domain.User{
			ID: ulid.New(), Email: email, Name: name, Roles: roles,
			Auth: domain.Auth{Local: &domain.LocalAuth{PasswordHash: hash}},
			Settings: domain.UserSettings{Theme: "light",
				Notifications: domain.NotificationPrefs{Email: true, InApp: true}},
			Bio: "Seeded demo account.",
		}
		if err := st.CreateUser(ctx, u); err != nil {
			log.Fatalf("create %s: %v", email, err)
		}
		fmt.Printf("  created: %s (password %q)\n", email, demoPassword)
		return u
	}

	fmt.Println("Seeding users…")
	user("seed-admin@example.com", "Seed Admin", domain.Roles{Admin: true})
	clara := user("clara@example.com", "Clara Consultant", domain.Roles{Consultant: true})
	carlos := user("carlos@example.com", "Carlos Consultant", domain.Roles{Consultant: true})
	devs := []*domain.User{}
	devNames := []string{"Dana", "Devon", "Dimitri", "Daria", "Dylan", "Drew"}
	for i, n := range devNames {
		devs = append(devs, user(fmt.Sprintf("dev%d@example.com", i+1),
			n+" Developer", domain.Roles{Developer: true}))
	}

	fmt.Println("Seeding pools…")
	addPool := func(c, d *domain.User) {
		if err := st.AddToPool(ctx, c.ID, d.ID); err != nil && err != store.ErrDuplicate {
			log.Fatalf("pool: %v", err)
		}
	}
	for _, d := range devs[:4] {
		addPool(clara, d)
	}
	for _, d := range devs[2:] {
		addPool(carlos, d)
	}

	fmt.Println("Seeding demo customer…")
	customers, err := st.ListCustomers(ctx, "", true)
	if err != nil {
		log.Fatal(err)
	}
	var demoCustomer *domain.Customer
	for i := range customers {
		if customers[i].Name == "ACME Demo" {
			demoCustomer = &customers[i]
		}
	}
	if demoCustomer == nil {
		demoCustomer = &domain.Customer{
			Name: "ACME Demo",
			Ticketing: domain.Ticketing{
				Type: domain.TicketingDemo, ProjectKey: "ACME", PollIntervalSec: 30,
			},
			ConsultantIDs: []string{clara.ID, carlos.ID},
			DefaultBudget: 1500,
		}
		if err := st.CreateCustomer(ctx, demoCustomer); err != nil {
			log.Fatal(err)
		}
		fmt.Println("  created: ACME Demo (demo ticketing — tickets appear within one poll)")
	} else {
		fmt.Println("  exists: ACME Demo")
	}

	fmt.Println("Seeding conversations…")
	dm, err := st.FindOrCreateDM(ctx, clara.ID, devs[0].ID)
	if err != nil {
		log.Fatal(err)
	}
	n, err := st.DB.Collection("messages").CountDocuments(ctx, bson.M{"conversationId": dm.ID})
	if err != nil {
		log.Fatal(err)
	}
	if n == 0 {
		msgs := []struct {
			from *domain.User
			body string
		}{
			{clara, "<p>Hi Dana — I just added you to my pool. The ACME board fills up shortly.</p>"},
			{devs[0], "<p>Great, I will grab the <b>CSV importer</b> once it is published.</p>"},
			{clara, "<p>Perfect. Ping me here if any acceptance criteria are unclear.</p>"},
		}
		for _, m := range msgs {
			if err := st.InsertMessage(ctx, &store.Message{
				ConversationID: dm.ID, SenderID: m.from.ID, Body: m.body,
			}); err != nil {
				log.Fatal(err)
			}
		}
		fmt.Println("  created: DM Clara ↔ Dana with 3 messages")
	}
	groups, _ := st.ListConversations(ctx, clara.ID)
	hasGroup := false
	for _, g := range groups {
		if g.Kind == "group" && g.Title == "ACME standup" {
			hasGroup = true
		}
	}
	if !hasGroup {
		grp := &store.Conversation{
			Kind: "group", Title: "ACME standup",
			ParticipantIDs: []string{clara.ID, carlos.ID, devs[0].ID, devs[1].ID, devs[2].ID},
		}
		if err := st.CreateConversation(ctx, grp); err != nil {
			log.Fatal(err)
		}
		if err := st.InsertMessage(ctx, &store.Message{
			ConversationID: grp.ID, SenderID: carlos.ID,
			Body: "<p>Welcome to the ACME standup channel. Daily updates here, please.</p>",
		}); err != nil {
			log.Fatal(err)
		}
		fmt.Println("  created: group 'ACME standup'")
	}

	fmt.Println("\nSeed complete.")
	fmt.Printf("Demo accounts (password %q):\n", demoPassword)
	fmt.Println("  seed-admin@example.com  (admin)")
	fmt.Println("  clara@example.com, carlos@example.com  (consultants)")
	for i := range devNames {
		fmt.Printf("  dev%d@example.com  (developer)\n", i+1)
	}
}
