package seeder

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
	"time"

	"github.com/gofrs/uuid/v5"
	_ "github.com/jackc/pgx/v5/stdlib"
	"github.com/jmoiron/sqlx"
	"golang.org/x/crypto/bcrypt"
)

// Anápolis, GO coordinates
const (
	AnapolisLat = -16.3281
	AnapolisLng = -48.9530
	VarianceKm  = 5.0 // ~5km spread
)

// Product categories with sample medicines
var categories = []string{
	"Analgésicos",
	"Antibióticos",
	"Anti-inflamatórios",
	"Cardiovasculares",
	"Dermatológicos",
	"Vitaminas",
	"Oftálmicos",
	"Respiratórios",
}

var medicamentos = []struct {
	Name      string
	Category  string
	BasePrice int64
}{
	{"Dipirona 500mg", "Analgésicos", 1299},
	{"Paracetamol 750mg", "Analgésicos", 899},
	{"Ibuprofeno 400mg", "Anti-inflamatórios", 1599},
	{"Nimesulida 100mg", "Anti-inflamatórios", 2499},
	{"Amoxicilina 500mg", "Antibióticos", 3499},
	{"Azitromicina 500mg", "Antibióticos", 4999},
	{"Losartana 50mg", "Cardiovasculares", 2199},
	{"Atenolol 50mg", "Cardiovasculares", 1899},
	{"Vitamina C 1g", "Vitaminas", 1599},
	{"Vitamina D 2000UI", "Vitaminas", 2299},
	{"Cetoconazol Creme", "Dermatológicos", 2899},
	{"Dexametasona Creme", "Dermatológicos", 1999},
	{"Colírio Lubrificante", "Oftálmicos", 3299},
	{"Lacrifilm 15ml", "Oftálmicos", 2899},
	{"Loratadina 10mg", "Respiratórios", 1799},
	{"Dexclorfeniramina 2mg", "Respiratórios", 1599},
	{"Omeprazol 20mg", "Gastrointestinais", 1999},
	{"Pantoprazol 40mg", "Gastrointestinais", 2999},
	{"Metformina 850mg", "Antidiabéticos", 1299},
	{"Glibenclamida 5mg", "Antidiabéticos", 999},
}

var pharmacyNames = []string{
	"Farmácia Popular", "Drogaria Central", "Farma Vida", "Drogasil",
	"Farmácia São João", "Droga Raia", "Ultrafarma", "Farma Bem",
	"Drogaria Moderna", "Farmácia União", "Saúde Total", "Bem Estar",
	"Vida Saudável", "Mais Saúde", "Farmácia do Povo", "Super Farma",
}

// Seed dispatches based on mode
func Seed(dsn, mode string) (string, error) {
	if mode == "lean" {
		return SeedLean(dsn)
	}
	return SeedFull(dsn)
}

func SeedLean(dsn string) (string, error) {
	if dsn == "" {
		return "", fmt.Errorf("DATABASE_URL not set")
	}

	db, err := sqlx.Connect("pgx", dsn)
	if err != nil {
		return "", fmt.Errorf("db connect: %v", err)
	}
	defer db.Close()

	ctx := context.Background()
	log.Println("🧹 [Lean] Resetting database...")

	// Re-create tables
	mustExec(db, `DROP TABLE IF EXISTS shipments CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS inventory_adjustments CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS order_items CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS orders CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS cart_items CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS reviews CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS products CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS users CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS companies CASCADE`)

	// Create tables (Schema must match backend migrations!)
	mustExec(db, `CREATE TABLE companies (
		id UUID PRIMARY KEY,
		cnpj TEXT NOT NULL UNIQUE,
		corporate_name TEXT NOT NULL,
		category TEXT NOT NULL DEFAULT 'farmacia',
		license_number TEXT NOT NULL,
		is_verified BOOLEAN NOT NULL DEFAULT FALSE,
		latitude DOUBLE PRECISION NOT NULL DEFAULT 0,
		longitude DOUBLE PRECISION NOT NULL DEFAULT 0,
		city TEXT NOT NULL DEFAULT '',
		state TEXT NOT NULL DEFAULT '',
		phone TEXT NOT NULL DEFAULT '',
		operating_hours TEXT NOT NULL DEFAULT '',
		is_24_hours BOOLEAN NOT NULL DEFAULT FALSE,
		created_at TIMESTAMPTZ NOT NULL,
		updated_at TIMESTAMPTZ NOT NULL
	)`)

	mustExec(db, `CREATE TABLE users (
        id UUID PRIMARY KEY,
        company_id UUID NOT NULL REFERENCES companies(id),
        role TEXT NOT NULL,
        name TEXT NOT NULL,
        username TEXT NOT NULL UNIQUE,
        email TEXT NOT NULL UNIQUE,
        email_verified BOOLEAN NOT NULL DEFAULT FALSE,
        password_hash TEXT NOT NULL,
        created_at TIMESTAMPTZ NOT NULL,
        updated_at TIMESTAMPTZ NOT NULL
    )`)

	mustExec(db, `CREATE TABLE products (
		id UUID PRIMARY KEY,
		seller_id UUID NOT NULL REFERENCES companies(id),
		ean_code TEXT NOT NULL DEFAULT '',
		name TEXT NOT NULL,
		description TEXT,
		manufacturer TEXT NOT NULL DEFAULT '',
		category TEXT NOT NULL DEFAULT '',
		subcategory TEXT NOT NULL DEFAULT '',
		batch TEXT NOT NULL,
		expires_at DATE NOT NULL,
		price_cents BIGINT NOT NULL,
		stock BIGINT NOT NULL,
		observations TEXT NOT NULL DEFAULT '',
		created_at TIMESTAMPTZ NOT NULL,
		updated_at TIMESTAMPTZ NOT NULL
	)`)

	mustExec(db, `CREATE TABLE orders (
		id UUID PRIMARY KEY,
		buyer_id UUID NOT NULL REFERENCES companies(id),
		seller_id UUID NOT NULL REFERENCES companies(id),
		status TEXT NOT NULL,
		total_cents BIGINT NOT NULL,
		shipping_recipient_name TEXT,
		shipping_street TEXT,
		shipping_number TEXT,
		shipping_complement TEXT,
		shipping_district TEXT,
		shipping_city TEXT,
		shipping_state TEXT,
		shipping_zip_code TEXT,
		shipping_country TEXT,
		created_at TIMESTAMPTZ NOT NULL,
		updated_at TIMESTAMPTZ NOT NULL
	)`)

	mustExec(db, `CREATE TABLE order_items (
		id UUID PRIMARY KEY,
		order_id UUID NOT NULL REFERENCES orders(id),
		product_id UUID NOT NULL REFERENCES products(id),
		quantity BIGINT NOT NULL,
		unit_cents BIGINT NOT NULL,
		batch TEXT NOT NULL,
		expires_at DATE NOT NULL
	)`)

	mustExec(db, `CREATE TABLE cart_items (
		id UUID PRIMARY KEY,
		buyer_id UUID NOT NULL REFERENCES companies(id),
		product_id UUID NOT NULL REFERENCES products(id),
		quantity BIGINT NOT NULL,
		unit_cents BIGINT NOT NULL,
		batch TEXT,
		expires_at DATE,
		created_at TIMESTAMPTZ NOT NULL,
		updated_at TIMESTAMPTZ NOT NULL,
		UNIQUE (buyer_id, product_id)
	)`)

	mustExec(db, `CREATE TABLE reviews (
		id UUID PRIMARY KEY,
		order_id UUID NOT NULL UNIQUE REFERENCES orders(id),
		buyer_id UUID NOT NULL REFERENCES companies(id),
		seller_id UUID NOT NULL REFERENCES companies(id),
		rating INT NOT NULL CHECK (rating BETWEEN 1 AND 5),
		comment TEXT,
		created_at TIMESTAMPTZ NOT NULL
	)`)

	mustExec(db, `CREATE TABLE shipments (
		id UUID PRIMARY KEY,
		order_id UUID NOT NULL UNIQUE REFERENCES orders(id),
		carrier TEXT NOT NULL,
		tracking_code TEXT,
		external_tracking TEXT,
		status TEXT NOT NULL,
		created_at TIMESTAMPTZ NOT NULL,
		updated_at TIMESTAMPTZ NOT NULL
	)`)

	// Helper for hashing
	hashPwd := func(pwd string) string {
		h, _ := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)
		return string(h)
	}
	defaultPwdHash := hashPwd("123456")

	// Fixed Pharmacies Data
	pharmacies := []struct {
		Name   string
		CNPJ   string
		Lat    float64
		Lng    float64
		Suffix string // for usernames/emails e.g. "1" -> dono1, email1
	}{
		{
			Name:   "Farmácia Central",
			CNPJ:   "11111111000111",
			Lat:    AnapolisLat,
			Lng:    AnapolisLng,
			Suffix: "1",
		},
		{
			Name:   "Farmácia Jundiaí",
			CNPJ:   "22222222000122",
			Lat:    AnapolisLat + 0.015, // Slightly North
			Lng:    AnapolisLng + 0.010, // East
			Suffix: "2",
		},
		{
			Name:   "Farmácia Jaiara",
			CNPJ:   "33333333000133",
			Lat:    AnapolisLat + 0.030, // More North
			Lng:    AnapolisLng - 0.010, // West
			Suffix: "3",
		},
		{
			Name:   "Farmácia Universitária",
			CNPJ:   "44444444000144",
			Lat:    AnapolisLat - 0.020, // South
			Lng:    AnapolisLng + 0.020, // East
			Suffix: "4",
		},
	}

	now := time.Now().UTC()
	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
	createdUsers := []string{}
	var allProducts []map[string]interface{}
	var pharmacyCompanyIDs []uuid.UUID

	for _, ph := range pharmacies {
		// 1. Create Company
		companyID := uuid.Must(uuid.NewV7())
		_, err = db.ExecContext(ctx, `
			INSERT INTO companies (id, cnpj, corporate_name, category, license_number, is_verified, latitude, longitude, city, state, phone, operating_hours, is_24_hours, created_at, updated_at)
			VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)`,
			companyID, ph.CNPJ, ph.Name, "farmacia", fmt.Sprintf("CRF-GO-%s", ph.Suffix), true, ph.Lat, ph.Lng, "Anápolis", "GO", "(62) 99999-00"+ph.Suffix, "Seg-Sex: 08:00-18:00, Sáb: 08:00-12:00", false, now, now,
		)
		if err != nil {
			return "", fmt.Errorf("create library %s: %v", ph.Name, err)
		}

		// 2. Create Users (Dono, Colab, Entregador)
		roles := []struct {
			Role     string
			UserBase string
			NameBase string
		}{
			{"Dono", "dono", "Dono"},
			{"Colaborador", "colab", "Colaborador"},
			{"Entregador", "entregador", "Entregador"},
		}

		for _, r := range roles {
			uid := uuid.Must(uuid.NewV7())
			username := fmt.Sprintf("%s%s", r.UserBase, ph.Suffix)
			email := fmt.Sprintf("%s%s@saveinmed.com", r.UserBase, ph.Suffix)
			name := fmt.Sprintf("%s %s", r.NameBase, ph.Name)

			mustExec(db, fmt.Sprintf(`INSERT INTO users (id, company_id, role, name, username, email, email_verified, password_hash, created_at, updated_at)
				VALUES ('%s', '%s', '%s', '%s', '%s', '%s', true, '%s', NOW(), NOW())`,
				uid, companyID, r.Role, name, username, email, defaultPwdHash,
			))
			createdUsers = append(createdUsers, fmt.Sprintf("%s (%s)", username, r.Role))
		}

		// 3. Create Products (20-50 products per pharmacy)
		numProds := 20 + rng.Intn(31) // 20-50
		prods := generateProducts(rng, companyID, numProds)
		for _, p := range prods {
			_, err := db.NamedExecContext(ctx, `
				INSERT INTO products (id, seller_id, ean_code, name, description, manufacturer, category, subcategory, batch, expires_at, price_cents, stock, observations, created_at, updated_at)
				VALUES (:id, :seller_id, :ean_code, :name, :description, :manufacturer, :category, :subcategory, :batch, :expires_at, :price_cents, :stock, :observations, :created_at, :updated_at)
				ON CONFLICT DO NOTHING`, p)
			if err != nil {
				log.Printf("insert product lean: %v", err)
			}
		}
		// Store products for orders/cart creation later
		allProducts = append(allProducts, prods...)
		pharmacyCompanyIDs = append(pharmacyCompanyIDs, companyID)
		log.Printf("✅ [Lean] %s created with %d products", ph.Name, len(prods))
	}

	// 4. Create some orders between pharmacies
	if len(allProducts) > 0 && len(pharmacyCompanyIDs) > 1 {
		// Create 5-10 orders
		numOrders := 5 + rng.Intn(6)
		for i := 0; i < numOrders; i++ {
			// Random buyer and seller (different companies)
			buyerIdx := rng.Intn(len(pharmacyCompanyIDs))
			sellerIdx := (buyerIdx + 1) % len(pharmacyCompanyIDs)
			buyerID := pharmacyCompanyIDs[buyerIdx]
			sellerID := pharmacyCompanyIDs[sellerIdx]

			// Find products from seller
			var sellerProducts []map[string]interface{}
			for _, p := range allProducts {
				if p["seller_id"].(uuid.UUID).String() == sellerID.String() {
					sellerProducts = append(sellerProducts, p)
				}
			}
			if len(sellerProducts) == 0 {
				continue
			}

			// Create order with 1-3 items
			orderID := uuid.Must(uuid.NewV7())
			statuses := []string{"Pendente", "Pago", "Faturado", "Entregue"}
			status := statuses[rng.Intn(len(statuses))]
			totalCents := int64(0)

			mustExec(db, fmt.Sprintf(`INSERT INTO orders (id, buyer_id, seller_id, status, total_cents, created_at, updated_at)
				VALUES ('%s', '%s', '%s', '%s', %d, NOW(), NOW())`,
				orderID, buyerID, sellerID, status, totalCents,
			))

			// Create order items
			numItems := 1 + rng.Intn(3)
			for j := 0; j < numItems && j < len(sellerProducts); j++ {
				prod := sellerProducts[rng.Intn(len(sellerProducts))]
				qty := int64(1 + rng.Intn(5))
				itemID := uuid.Must(uuid.NewV7())
				priceCents := prod["price_cents"].(int64)
				totalCents += priceCents * qty

				mustExec(db, fmt.Sprintf(`INSERT INTO order_items (id, order_id, product_id, quantity, unit_cents, batch, expires_at)
					VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s')`,
					itemID, orderID, prod["id"].(uuid.UUID), qty, priceCents, prod["batch"].(string), prod["expires_at"].(time.Time).Format(time.RFC3339),
				))
			}

			// Update total cents on order because it we calculated it inside the loop
			mustExec(db, fmt.Sprintf(`UPDATE orders SET total_cents = %d WHERE id = '%s'`, totalCents, orderID))

			// Create Review if Delivered
			if status == "Entregue" {
				rating := 3 + rng.Intn(3) // 3-5 stars
				comment := []string{"Ótimo atendimento!", "Entrega rápida", "Recomendo", "Tudo certo"}[rng.Intn(4)]
				mustExec(db, fmt.Sprintf(`INSERT INTO reviews (id, order_id, buyer_id, seller_id, rating, comment, created_at)
					VALUES ('%s', '%s', '%s', '%s', %d, '%s', NOW())`,
					uuid.Must(uuid.NewV7()), orderID, buyerID, sellerID, rating, comment,
				))
			}

			// Create Shipment if Faturado or Entregue
			if status == "Faturado" || status == "Entregue" {
				carrier := []string{"Correios", "Loggi", "TotalExpress"}[rng.Intn(3)]
				tracking := fmt.Sprintf("TRK-%d%d", rng.Intn(1000), rng.Intn(1000))
				mustExec(db, fmt.Sprintf(`INSERT INTO shipments (id, order_id, carrier, tracking_code, external_tracking, status, created_at, updated_at)
					VALUES ('%s', '%s', '%s', '%s', '', 'Enviado', NOW(), NOW())`,
					uuid.Must(uuid.NewV7()), orderID, carrier, tracking,
				))
			}
		}
		log.Printf("✅ [Lean] Created %d orders", numOrders)

		// 5. Add cart items for first pharmacy
		if len(pharmacyCompanyIDs) > 0 && len(allProducts) > 3 {
			buyerID := pharmacyCompanyIDs[0]
			for i := 0; i < 3; i++ {
				prod := allProducts[rng.Intn(len(allProducts))]
				if prod["seller_id"].(uuid.UUID).String() == buyerID.String() {
					continue // Skip own products
				}
				cartItemID := uuid.Must(uuid.NewV7())
				qty := int64(1 + rng.Intn(3))
				priceCents := prod["price_cents"].(int64)
				mustExec(db, fmt.Sprintf(`INSERT INTO cart_items (id, buyer_id, product_id, quantity, unit_cents, created_at, updated_at)
					VALUES ('%s', '%s', '%s', %d, %d, NOW(), NOW()) ON CONFLICT DO NOTHING`,
					cartItemID, buyerID, prod["id"].(uuid.UUID), qty, priceCents,
				))
			}
			log.Printf("✅ [Lean] Added cart items")
		}
	}

	// 6. Create Global Admin (linked to first pharmacy for FK constraint)
	var centralID string
	err = db.Get(&centralID, "SELECT id FROM companies WHERE cnpj = '11111111000111'")
	if err == nil {
		adminID := uuid.Must(uuid.NewV7())
		mustExec(db, fmt.Sprintf(`INSERT INTO users (id, company_id, role, name, username, email, email_verified, password_hash, created_at, updated_at)
			VALUES ('%s', '%s', 'Admin', 'Administrador Global', 'admin', 'admin@saveinmed.com', true, '%s', NOW(), NOW())`,
			adminID, centralID, hashPwd("admin123"),
		))
		createdUsers = append(createdUsers, "admin (Admin)")
	}

	return fmt.Sprintf("Lean seed completed. 4 Pharmacies. Users: %d. Pass: 123456 (admin: admin123)", len(createdUsers)), nil
}

func SeedFull(dsn string) (string, error) {
	if dsn == "" {
		return "", fmt.Errorf("DATABASE_URL not set")
	}

	db, err := sqlx.Connect("pgx", dsn)
	if err != nil {
		return "", fmt.Errorf("db connect: %v", err)
	}
	defer db.Close()

	ctx := context.Background()
	rng := rand.New(rand.NewSource(time.Now().UnixNano()))

	// Re-create tables to ensure schema match
	log.Println("Re-creating tables...")
	mustExec(db, `DROP TABLE IF EXISTS inventory_adjustments CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS order_items CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS orders CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS cart_items CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS reviews CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS products CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS users CASCADE`)
	mustExec(db, `DROP TABLE IF EXISTS companies CASCADE`)

	mustExec(db, `CREATE TABLE companies (
		id UUID PRIMARY KEY,
		cnpj TEXT NOT NULL UNIQUE,
		corporate_name TEXT NOT NULL,
		category TEXT NOT NULL DEFAULT 'farmacia',
		license_number TEXT NOT NULL,
		is_verified BOOLEAN NOT NULL DEFAULT FALSE,
		latitude DOUBLE PRECISION NOT NULL DEFAULT 0,
		longitude DOUBLE PRECISION NOT NULL DEFAULT 0,
		city TEXT NOT NULL DEFAULT '',
		state TEXT NOT NULL DEFAULT '',
		phone TEXT NOT NULL DEFAULT '',
		operating_hours TEXT NOT NULL DEFAULT '',
		is_24_hours BOOLEAN NOT NULL DEFAULT FALSE,
		created_at TIMESTAMPTZ NOT NULL,
		updated_at TIMESTAMPTZ NOT NULL
	)`)

	mustExec(db, `CREATE TABLE users (
        id UUID PRIMARY KEY,
        company_id UUID NOT NULL REFERENCES companies(id),
        role TEXT NOT NULL,
        name TEXT NOT NULL,
        username TEXT NOT NULL UNIQUE,
        email TEXT NOT NULL UNIQUE,
        email_verified BOOLEAN NOT NULL DEFAULT FALSE,
        password_hash TEXT NOT NULL,
        created_at TIMESTAMPTZ NOT NULL,
        updated_at TIMESTAMPTZ NOT NULL
    )`)

	mustExec(db, `CREATE TABLE products (
		id UUID PRIMARY KEY,
		seller_id UUID NOT NULL REFERENCES companies(id),
		ean_code TEXT NOT NULL DEFAULT '',
		name TEXT NOT NULL,
		description TEXT,
		manufacturer TEXT NOT NULL DEFAULT '',
		category TEXT NOT NULL DEFAULT '',
		subcategory TEXT NOT NULL DEFAULT '',
		batch TEXT NOT NULL,
		expires_at DATE NOT NULL,
		price_cents BIGINT NOT NULL,
		stock BIGINT NOT NULL,
		observations TEXT NOT NULL DEFAULT '',
		created_at TIMESTAMPTZ NOT NULL,
		updated_at TIMESTAMPTZ NOT NULL
	)`)

	// Generate 400 tenants
	tenants := generateTenants(rng, 400)
	log.Printf("Generated %d tenants", len(tenants))

	// Insert tenants
	for _, t := range tenants {
		_, err := db.NamedExecContext(ctx, `
			INSERT INTO companies (id, cnpj, corporate_name, category, license_number, is_verified, latitude, longitude, city, state, phone, operating_hours, is_24_hours, created_at, updated_at)
			VALUES (:id, :cnpj, :corporate_name, :category, :license_number, :is_verified, :latitude, :longitude, :city, :state, :phone, :operating_hours, :is_24_hours, :created_at, :updated_at)
			ON CONFLICT (cnpj) DO NOTHING`, t)
		if err != nil {
			log.Printf("insert tenant %s: %v", t["corporate_name"], err)
		}
	}
	log.Println("Tenants inserted")

	// Generate and insert products for each tenant
	totalProducts := 0
	for _, t := range tenants {
		tenantID := t["id"].(uuid.UUID)
		numProducts := 20 + rng.Intn(481) // 20-500
		products := generateProducts(rng, tenantID, numProducts)
		totalProducts += len(products)

		for _, p := range products {
			_, err := db.NamedExecContext(ctx, `
				INSERT INTO products (id, seller_id, name, description, batch, description, expires_at, price_cents, stock, created_at, updated_at)
				VALUES (:id, :seller_id, :name, :description, :batch, :description, :expires_at, :price_cents, :stock, :created_at, :updated_at)
				ON CONFLICT DO NOTHING`, p)
			if err != nil {
				// Try again with minimal columns if the issue is named params mismatch
				// Wait, I see duplicate description in named exec above?
				// ORIGINAL:
				// INSERT INTO products (id, seller_id, name, description, batch, expires_at, price_cents, stock, created_at, updated_at)
				// VALUES (:id, :seller_id, :name, :description, :batch, :expires_at, :price_cents, :stock, :created_at, :updated_at)

				// I should verify the original file content.
				// Line 152: INSERT INTO products (id, seller_id, name, description, batch, expires_at, price_cents, stock, created_at, updated_at)
				// Line 153: VALUES (:id, :seller_id, :name, :description, :batch, :expires_at, :price_cents, :stock, :created_at, :updated_at)

				// I will correct my manual typing in this block to match original.

				_, err = db.NamedExecContext(ctx, `
					INSERT INTO products (id, seller_id, name, description, batch, expires_at, price_cents, stock, created_at, updated_at)
					VALUES (:id, :seller_id, :name, :description, :batch, :expires_at, :price_cents, :stock, :created_at, :updated_at)
					ON CONFLICT DO NOTHING`, p)

				if err != nil {
					log.Printf("insert product: %v", err)
				}
			}
		}
	}
	log.Printf("Inserted %d products total", totalProducts)

	// Output summary
	summary := map[string]interface{}{
		"tenants":  len(tenants),
		"products": totalProducts,
		"location": "Anápolis, GO",
	}
	out, _ := json.MarshalIndent(summary, "", "  ")
	return string(out), nil
}

func generateTenants(rng *rand.Rand, count int) []map[string]interface{} {
	now := time.Now().UTC()
	tenants := make([]map[string]interface{}, 0, count)

	for i := 0; i < count; i++ {
		id, _ := uuid.NewV4()
		name := fmt.Sprintf("%s %d", pharmacyNames[rng.Intn(len(pharmacyNames))], i+1)
		cnpj := generateCNPJ(rng)

		// Vary lat/lng within ~5km of Anápolis center
		latOffset := (rng.Float64() - 0.5) * 0.09 // ~5km
		lngOffset := (rng.Float64() - 0.5) * 0.09

		tenants = append(tenants, map[string]interface{}{
			"id":              id,
			"cnpj":            cnpj,
			"corporate_name":  name,
			"category":        "farmacia",
			"license_number":  fmt.Sprintf("CRF-GO-%05d", rng.Intn(99999)),
			"is_verified":     rng.Float32() > 0.3, // 70% verified
			"latitude":        AnapolisLat + latOffset,
			"longitude":       AnapolisLng + lngOffset,
			"city":            "Anápolis",
			"state":           "GO",
			"phone":           fmt.Sprintf("(62) 9%04d-%04d", rng.Intn(9999), rng.Intn(9999)),
			"operating_hours": "Seg-Sex: 08:00-18:00",
			"is_24_hours":     rng.Float32() < 0.1, // 10% are 24h
			"created_at":      now,
			"updated_at":      now,
		})
	}
	return tenants
}

func generateProducts(rng *rand.Rand, sellerID uuid.UUID, count int) []map[string]interface{} {
	now := time.Now().UTC()
	products := make([]map[string]interface{}, 0, count)

	for i := 0; i < count; i++ {
		id, _ := uuid.NewV4()
		med := medicamentos[rng.Intn(len(medicamentos))]

		// Random expiration: 30 days to 2 years from now
		daysToExpire := 30 + rng.Intn(700)
		expiresAt := now.AddDate(0, 0, daysToExpire)

		// Price variation: -20% to +30%
		priceMultiplier := 0.8 + rng.Float64()*0.5
		price := int64(float64(med.BasePrice) * priceMultiplier)

		products = append(products, map[string]interface{}{
			"id":           id,
			"seller_id":    sellerID,
			"ean_code":     fmt.Sprintf("789%010d", rng.Int63n(9999999999)),
			"name":         med.Name,
			"description":  fmt.Sprintf("%s - %s", med.Name, med.Category),
			"manufacturer": []string{"EMS", "Medley", "Neo Química", "Eurofarma", "Aché", "Sanofi"}[rng.Intn(6)],
			"category":     med.Category,
			"subcategory":  "",
			"batch":        fmt.Sprintf("L%d%03d", now.Year(), rng.Intn(999)),
			"expires_at":   expiresAt,
			"price_cents":  price,
			"stock":        int64(10 + rng.Intn(500)),
			"observations": "",
			"created_at":   now,
			"updated_at":   now,
		})
	}
	return products
}

func generateCNPJ(rng *rand.Rand) string {
	return fmt.Sprintf("%02d.%03d.%03d/%04d-%02d",
		rng.Intn(99), rng.Intn(999), rng.Intn(999),
		rng.Intn(9999)+1, rng.Intn(99))
}

func mustExec(db *sqlx.DB, query string) {
	_, err := db.Exec(query)
	if err != nil {
		log.Printf("exec %s: %v", query, err) // Don't fatal, just log
	}
}
