package store

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/google/uuid"

	ext "git.warky.dev/wdevs/amcs/internal/types"
)

func (db *DB) AddHouseholdItem(ctx context.Context, item ext.HouseholdItem) (ext.HouseholdItem, error) {
	details, err := json.Marshal(item.Details)
	if err != nil {
		return ext.HouseholdItem{}, fmt.Errorf("marshal details: %w", err)
	}

	row := db.pool.QueryRow(ctx, `
		insert into household_items (name, category, location, details, notes)
		values ($1, $2, $3, $4::jsonb, $5)
		returning id, created_at, updated_at
	`, item.Name, nullStr(item.Category), nullStr(item.Location), details, nullStr(item.Notes))

	created := item
	if err := row.Scan(&created.ID, &created.CreatedAt, &created.UpdatedAt); err != nil {
		return ext.HouseholdItem{}, fmt.Errorf("insert household item: %w", err)
	}
	return created, nil
}

func (db *DB) SearchHouseholdItems(ctx context.Context, query, category, location string) ([]ext.HouseholdItem, error) {
	args := []any{}
	conditions := []string{}

	if q := strings.TrimSpace(query); q != "" {
		args = append(args, "%"+q+"%")
		conditions = append(conditions, fmt.Sprintf("(name ILIKE $%d OR notes ILIKE $%d)", len(args), len(args)))
	}
	if c := strings.TrimSpace(category); c != "" {
		args = append(args, c)
		conditions = append(conditions, fmt.Sprintf("category = $%d", len(args)))
	}
	if l := strings.TrimSpace(location); l != "" {
		args = append(args, "%"+l+"%")
		conditions = append(conditions, fmt.Sprintf("location ILIKE $%d", len(args)))
	}

	q := `select id, name, category, location, details, notes, created_at, updated_at from household_items`
	if len(conditions) > 0 {
		q += " where " + strings.Join(conditions, " and ")
	}
	q += " order by name"

	rows, err := db.pool.Query(ctx, q, args...)
	if err != nil {
		return nil, fmt.Errorf("search household items: %w", err)
	}
	defer rows.Close()

	var items []ext.HouseholdItem
	for rows.Next() {
		var item ext.HouseholdItem
		var detailsBytes []byte
		var category, location, notes *string
		if err := rows.Scan(&item.ID, &item.Name, &category, &location, &detailsBytes, &notes, &item.CreatedAt, &item.UpdatedAt); err != nil {
			return nil, fmt.Errorf("scan household item: %w", err)
		}
		item.Category = strVal(category)
		item.Location = strVal(location)
		item.Notes = strVal(notes)
		if err := json.Unmarshal(detailsBytes, &item.Details); err != nil {
			item.Details = map[string]any{}
		}
		items = append(items, item)
	}
	return items, rows.Err()
}

func (db *DB) GetHouseholdItem(ctx context.Context, id uuid.UUID) (ext.HouseholdItem, error) {
	row := db.pool.QueryRow(ctx, `
		select id, name, category, location, details, notes, created_at, updated_at
		from household_items where id = $1
	`, id)

	var item ext.HouseholdItem
	var detailsBytes []byte
	var category, location, notes *string
	if err := row.Scan(&item.ID, &item.Name, &category, &location, &detailsBytes, &notes, &item.CreatedAt, &item.UpdatedAt); err != nil {
		return ext.HouseholdItem{}, fmt.Errorf("get household item: %w", err)
	}
	item.Category = strVal(category)
	item.Location = strVal(location)
	item.Notes = strVal(notes)
	if err := json.Unmarshal(detailsBytes, &item.Details); err != nil {
		item.Details = map[string]any{}
	}
	return item, nil
}

func (db *DB) AddVendor(ctx context.Context, v ext.HouseholdVendor) (ext.HouseholdVendor, error) {
	row := db.pool.QueryRow(ctx, `
		insert into household_vendors (name, service_type, phone, email, website, notes, rating, last_used)
		values ($1, $2, $3, $4, $5, $6, $7, $8)
		returning id, created_at
	`, v.Name, nullStr(v.ServiceType), nullStr(v.Phone), nullStr(v.Email),
		nullStr(v.Website), nullStr(v.Notes), v.Rating, v.LastUsed)

	created := v
	if err := row.Scan(&created.ID, &created.CreatedAt); err != nil {
		return ext.HouseholdVendor{}, fmt.Errorf("insert vendor: %w", err)
	}
	return created, nil
}

func (db *DB) ListVendors(ctx context.Context, serviceType string) ([]ext.HouseholdVendor, error) {
	args := []any{}
	q := `select id, name, service_type, phone, email, website, notes, rating, last_used, created_at from household_vendors`
	if st := strings.TrimSpace(serviceType); st != "" {
		args = append(args, st)
		q += " where service_type = $1"
	}
	q += " order by name"

	rows, err := db.pool.Query(ctx, q, args...)
	if err != nil {
		return nil, fmt.Errorf("list vendors: %w", err)
	}
	defer rows.Close()

	var vendors []ext.HouseholdVendor
	for rows.Next() {
		var v ext.HouseholdVendor
		var serviceType, phone, email, website, notes *string
		var lastUsed *time.Time
		if err := rows.Scan(&v.ID, &v.Name, &serviceType, &phone, &email, &website, &notes, &v.Rating, &lastUsed, &v.CreatedAt); err != nil {
			return nil, fmt.Errorf("scan vendor: %w", err)
		}
		v.ServiceType = strVal(serviceType)
		v.Phone = strVal(phone)
		v.Email = strVal(email)
		v.Website = strVal(website)
		v.Notes = strVal(notes)
		v.LastUsed = lastUsed
		vendors = append(vendors, v)
	}
	return vendors, rows.Err()
}
