package main

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

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

	"github.com/saveinmed/backend-go/internal/config"
	"github.com/saveinmed/backend-go/internal/domain"
)

func main() {
	cfg, err := config.Load()
	if err != nil {
		log.Fatalf("failed to load config: %v", err)
	}

	db, err := sqlx.Open("pgx", cfg.DatabaseURL)
	if err != nil {
		log.Fatalf("Failed to connect to DB: %v", err)
	}
	defer db.Close()

	if err := db.Ping(); err != nil {
		log.Fatalf("Failed to ping DB: %v", err)
	}

	ctx := context.Background()

	log.Println("🧹 Cleaning database...")
	cleanDB(ctx, db)

	log.Println("🌱 Seeding data...")
	seedData(ctx, db, *cfg)

	log.Println("✅ Seeding complete!")
}

func cleanDB(ctx context.Context, db *sqlx.DB) {
	tables := []string{
		"reviews", "shipments", "payment_preferences", "orders", "order_items",
		"cart_items", "products", "companies", "users", "shipping_settings",
	}

	for _, table := range tables {
		_, err := db.ExecContext(ctx, fmt.Sprintf("TRUNCATE TABLE %s CASCADE", table))
		if err != nil {
			// Ignore error if table doesn't exist or is empty
			log.Printf("Warning cleaning %s: %v", table, err)
		}
	}
}

func seedData(ctx context.Context, db *sqlx.DB, cfg config.Config) {
	// 1. Seed Admin
	adminCompanyID := uuid.Must(uuid.NewV7())
	createCompany(ctx, db, &domain.Company{
		ID:            adminCompanyID,
		CNPJ:          "00000000000000",
		CorporateName: "SaveInMed Admin",
		Category:      "admin",
		LicenseNumber: "ADMIN",
		IsVerified:    true,
	})
	createUser(ctx, db, &domain.User{
		CompanyID: adminCompanyID,
		Role:      "Admin",
		Name:      cfg.AdminName,
		Username:  cfg.AdminUsername,
		Email:     cfg.AdminEmail,
	}, cfg.AdminPassword, cfg.PasswordPepper)

	// 2. Distributors (Sellers - SP Center)
	distributor1ID := uuid.Must(uuid.NewV7())
	createCompany(ctx, db, &domain.Company{
		ID:            distributor1ID,
		CNPJ:          "11111111000111",
		CorporateName: "Distribuidora Nacional",
		Category:      "distribuidora",
		LicenseNumber: "DIST-001",
		IsVerified:    true,
		Latitude:      -23.55052,
		Longitude:     -46.633308,
	})
	createUser(ctx, db, &domain.User{
		CompanyID: distributor1ID,
		Role:      "Owner",
		Name:      "Dono da Distribuidora",
		Username:  "distribuidora",
		Email:     "distribuidora@saveinmed.com",
	}, "123456", cfg.PasswordPepper)
	createShippingSettings(ctx, db, distributor1ID, -23.55052, -46.633308, "Rua da Distribuidora, 1000")

	// 2b. Second Distributor (Sellers - SP East Zone/Mooca)
	distributor2ID := uuid.Must(uuid.NewV7())
	createCompany(ctx, db, &domain.Company{
		ID:            distributor2ID,
		CNPJ:          "55555555000555",
		CorporateName: "Distribuidora Leste Ltda",
		Category:      "distribuidora",
		LicenseNumber: "DIST-002",
		IsVerified:    true,
		Latitude:      -23.55952,
		Longitude:     -46.593308,
	})
	createUser(ctx, db, &domain.User{
		CompanyID: distributor2ID,
		Role:      "Owner",
		Name:      "Gerente Leste",
		Username:  "distribuidora_leste",
		Email:     "leste@saveinmed.com",
	}, "123456", cfg.PasswordPepper)
	createShippingSettings(ctx, db, distributor2ID, -23.55952, -46.593308, "Rua da Mooca, 500")

	// 3. Pharmacies (Buyers)
	pharmacy1ID := uuid.Must(uuid.NewV7())
	createCompany(ctx, db, &domain.Company{
		ID:            pharmacy1ID,
		CNPJ:          "22222222000122",
		CorporateName: "Farmácia Central",
		Category:      "farmacia",
		LicenseNumber: "FARM-001",
		IsVerified:    true,
		Latitude:      -23.56052,
		Longitude:     -46.643308,
	})
	createUser(ctx, db, &domain.User{
		CompanyID: pharmacy1ID,
		Role:      "Owner",
		Name:      "Dono da Farmácia",
		Username:  "farmacia",
		Email:     "farmacia@saveinmed.com",
	}, "123456", cfg.PasswordPepper)

	pharmacy2ID := uuid.Must(uuid.NewV7())
	createCompany(ctx, db, &domain.Company{
		ID:            pharmacy2ID,
		CNPJ:          "33333333000133",
		CorporateName: "Drogarias Tiete",
		Category:      "farmacia",
		LicenseNumber: "FARM-002",
		IsVerified:    true,
		Latitude:      -23.51052,
		Longitude:     -46.613308,
	})
	createUser(ctx, db, &domain.User{
		CompanyID: pharmacy2ID,
		Role:      "Owner",
		Name:      "Gerente Tiete",
		Username:  "farmacia2",
		Email:     "tiete@saveinmed.com",
	}, "123456", cfg.PasswordPepper)

	// 4. Products
	// List of diverse products
	commonMeds := []struct {
		Name  string
		Price int64 // Base price
	}{
		{"Dipirona Sódica 500mg", 450},
		{"Paracetamol 750mg", 600},
		{"Ibuprofeno 400mg", 1100},
		{"Amoxicilina 500mg", 2200},
		{"Omeprazol 20mg", 1400},
		{"Simeticona 40mg", 700},
		{"Dorflex 36cp", 1850},
		{"Neosaldina 30dg", 2100},
		{"Torsilax 30cp", 1200},
		{"Cimegripe 20caps", 1300},
		{"Losartana Potássica 50mg", 800},
		{"Atenolol 25mg", 950},
		{"Metformina 850mg", 750},
		{"Sildenafila 50mg", 1500},
		{"Azitromicina 500mg", 2800},
	}

	var productIDs []uuid.UUID

	// Seed products for Dist 1
	for i, p := range commonMeds {
		id := uuid.Must(uuid.NewV7())
		// expiry := time.Now().AddDate(1, 0, 0)

		// Vary price slightly
		finalPrice := p.Price + int64(i*10) - 50
		if finalPrice < 100 {
			finalPrice = 100
		}

		createProduct(ctx, db, &domain.Product{
			ID:          id,
			SellerID:    distributor1ID,
			Name:        p.Name,
			Description: "Medicamento genérico de alta qualidade (Nacional)",
			// Batch/ExpiresAt/Stock removed
			PriceCents: finalPrice,
		})

		// Keep first 5 for orders
		if i < 5 {
			productIDs = append(productIDs, id)
		}
	}

	// Seed products for Dist 2 (Leste) - Only some of them, different prices
	for i, p := range commonMeds {
		if i%2 == 0 {
			continue
		} // Skip half

		id := uuid.Must(uuid.NewV7())
		// expiry := time.Now().AddDate(0, 6, 0) // Removed

		// Cheaper but fewer stock
		finalPrice := p.Price - 100
		if finalPrice < 100 {
			finalPrice = 100
		}

		createProduct(ctx, db, &domain.Product{
			ID:          id,
			SellerID:    distributor2ID,
			Name:        p.Name,
			Description: "Distribuição exclusiva ZL",
			// Batch/ExpiresAt/Stock removed
			PriceCents: finalPrice,
		})
	}

	// 5. Orders
	// Order 1: Pharmacy 1 buying from Dist 1
	orderID := uuid.Must(uuid.NewV7())
	totalCents := int64(0)

	// Items
	qty := int64(10)
	priceItem := productIDs[0] // Dipirona from Dist 1
	// We need to fetch price ideally but we know logic... let's just reuse base logic approx or fetch from struct above
	// Simulating price:
	unitPrice := commonMeds[0].Price - 50 // Same logic as above: p.Price + 0*10 - 50

	itemTotal := unitPrice * qty
	totalCents += itemTotal

	createOrder(ctx, db, &domain.Order{
		ID:         orderID,
		BuyerID:    pharmacy1ID,
		SellerID:   distributor1ID,
		Status:     "Faturado", // Ready for "Confirmar Entrega" test
		TotalCents: totalCents,
		CreatedAt:  time.Now().AddDate(0, 0, -2),
		UpdatedAt:  time.Now(),
	})

	createOrderItem(ctx, db, &domain.OrderItem{
		ID:        uuid.Must(uuid.NewV7()),
		OrderID:   orderID,
		ProductID: priceItem,
		Quantity:  qty,
		UnitCents: unitPrice,
		Batch:     "BATCH-NAC-" + priceItem.String()[:4],
		ExpiresAt: time.Now().AddDate(1, 0, 0),
	})

	// Order 2: Pharmacy 2 buying from Dist 1 (Pending)
	order2ID := uuid.Must(uuid.NewV7())
	createOrder(ctx, db, &domain.Order{
		ID:         order2ID,
		BuyerID:    pharmacy2ID,
		SellerID:   distributor1ID,
		Status:     "Pendente",
		TotalCents: 5000,
		CreatedAt:  time.Now(),
		UpdatedAt:  time.Now(),
	})

}

func createCompany(ctx context.Context, db *sqlx.DB, c *domain.Company) {
	now := time.Now().UTC()
	c.CreatedAt = now
	c.UpdatedAt = now
	_, err := db.NamedExecContext(ctx, `
		INSERT INTO companies (id, cnpj, corporate_name, category, license_number, is_verified, latitude, longitude, created_at, updated_at)
		VALUES (:id, :cnpj, :corporate_name, :category, :license_number, :is_verified, :latitude, :longitude, :created_at, :updated_at)
	`, c)
	if err != nil {
		log.Printf("Error creating company %s: %v", c.CorporateName, err)
	}
}

func createUser(ctx context.Context, db *sqlx.DB, u *domain.User, password, pepper string) {
	hashed, _ := bcrypt.GenerateFromPassword([]byte(password+pepper), bcrypt.DefaultCost)
	u.ID = uuid.Must(uuid.NewV7())
	u.PasswordHash = string(hashed)
	u.CreatedAt = time.Now().UTC()
	u.UpdatedAt = time.Now().UTC()

	// Ensure email/username uniqueness is handled by DB constraint, usually we just insert
	_, err := db.NamedExecContext(ctx, `
		INSERT INTO users (id, company_id, role, name, username, email, password_hash, email_verified, created_at, updated_at)
		VALUES (:id, :company_id, :role, :name, :username, :email, :password_hash, :email_verified, :created_at, :updated_at)
	`, u)
	if err != nil {
		log.Printf("Error creating user %s: %v", u.Username, err)
	}
}

func createProduct(ctx context.Context, db *sqlx.DB, p *domain.Product) {
	now := time.Now().UTC()
	p.CreatedAt = now
	p.UpdatedAt = now
	_, err := db.NamedExecContext(ctx, `
		INSERT INTO products (id, seller_id, name, description, price_cents, created_at, updated_at)
		VALUES (:id, :seller_id, :name, :description, :price_cents, :created_at, :updated_at)
	`, p)
	if err != nil {
		log.Printf("Error creating product %s: %v", p.Name, err)
	}
}

func createShippingSettings(ctx context.Context, db *sqlx.DB, vendorID uuid.UUID, lat, lng float64, address string) {
	now := time.Now().UTC()
	settings := &domain.ShippingSettings{
		VendorID:                   vendorID,
		Active:                     true,
		MaxRadiusKm:                50,
		PricePerKmCents:            150,  // R$ 1.50
		MinFeeCents:                1000, // R$ 10.00
		FreeShippingThresholdCents: nil,
		PickupActive:               true,
		PickupAddress:              address,
		PickupHours:                "Seg-Sex 08-18h",
		CreatedAt:                  now,
		UpdatedAt:                  now,
		Latitude:                   lat,
		Longitude:                  lng,
	}

	_, err := db.NamedExecContext(ctx, `
		INSERT INTO shipping_settings (
			vendor_id, active, max_radius_km, price_per_km_cents, min_fee_cents, 
			free_shipping_threshold_cents, pickup_active, pickup_address, pickup_hours, 
			latitude, longitude, created_at, updated_at
		) VALUES (
			:vendor_id, :active, :max_radius_km, :price_per_km_cents, :min_fee_cents,
			:free_shipping_threshold_cents, :pickup_active, :pickup_address, :pickup_hours,
			:latitude, :longitude, :created_at, :updated_at
		)
	`, settings)
	if err != nil {
		log.Printf("Error creating shipping settings: %v", err)
	}
}

func createOrder(ctx context.Context, db *sqlx.DB, o *domain.Order) {
	_, err := db.NamedExecContext(ctx, `
		INSERT INTO orders (id, buyer_id, seller_id, status, total_cents, created_at, updated_at)
		VALUES (:id, :buyer_id, :seller_id, :status, :total_cents, :created_at, :updated_at)
	`, o)
	if err != nil {
		log.Printf("Error creating order: %v", err)
	}
}

func createOrderItem(ctx context.Context, db *sqlx.DB, item *domain.OrderItem) {
	_, err := db.NamedExecContext(ctx, `
		INSERT INTO order_items (id, order_id, product_id, quantity, unit_cents, batch, expires_at)
		VALUES (:id, :order_id, :product_id, :quantity, :unit_cents, :batch, :expires_at)
	`, item)
	if err != nil {
		log.Printf("Error creating order item: %v", err)
	}
}
