package warehouses

import (
	"context"
	"errors"

	"github.com/TaruLab/keluargamart-backend/internal/db"
	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/pgxpool"
	"github.com/shopspring/decimal"
)

// Repository implements Store on a pgx pool.
type Repository struct {
	pool *pgxpool.Pool
	q    *db.Queries
}

func NewRepository(pool *pgxpool.Pool) *Repository {
	return &Repository{pool: pool, q: db.New(pool)}
}

// warehouses has no deleted_at (docs/database-analysis.md §3): no soft delete.

func (r *Repository) List(ctx context.Context, page, perPage int, search string) ([]db.Warehouse, int, error) {
	total, err := r.q.CountWarehouses(ctx, search)
	if err != nil {
		return nil, 0, err
	}
	rows, err := r.q.ListWarehouses(ctx, db.ListWarehousesParams{
		Column1: search,
		Limit:   int32(perPage),
		Offset:  int32((page - 1) * perPage),
	})
	if err != nil {
		return nil, 0, err
	}
	out := make([]db.Warehouse, 0, len(rows))
	for _, rw := range rows {
		out = append(out, db.Warehouse{
			ID:       rw.ID,
			Code:     rw.Code,
			Name:     rw.Name,
			Address:  rw.Address,
			IsActive: rw.IsActive,
		})
	}
	return out, int(total), nil
}

// Options returns the slim active-warehouse list for checkout pickers via a
// dedicated lightweight query (no pagination/joins like List).
func (r *Repository) Options(ctx context.Context) ([]Option, error) {
	rows, err := r.q.ListWarehouseOptions(ctx)
	if err != nil {
		return nil, err
	}
	out := make([]Option, 0, len(rows))
	for _, row := range rows {
		out = append(out, Option{ID: row.ID, Code: row.Code, Name: row.Name, Latitude: decimalPtr(row.Latitude), Longitude: decimalPtr(row.Longitude)})
	}
	return out, nil
}

// decimalPtr maps a nullable numeric to an optional coordinate (SQL NULL → nil).
func decimalPtr(d decimal.NullDecimal) *decimal.Decimal {
	if !d.Valid {
		return nil
	}
	v := d.Decimal
	return &v
}

func (r *Repository) ByID(ctx context.Context, id int64) (*db.Warehouse, error) {
	row, err := r.q.GetWarehouseByID(ctx, id)
	if err != nil {
		if errors.Is(err, pgx.ErrNoRows) {
			return nil, ErrNotFound
		}
		return nil, err
	}
	return &db.Warehouse{
		ID:       row.ID,
		Code:     row.Code,
		Name:     row.Name,
		Address:  row.Address,
		IsActive: row.IsActive,
		Latitude: row.Latitude, Longitude: row.Longitude,
	}, nil
}

func (r *Repository) Create(ctx context.Context, w *db.Warehouse) error {
	id, err := r.q.CreateWarehouse(ctx, db.CreateWarehouseParams{
		Code:     w.Code,
		Name:     w.Name,
		Address:  w.Address,
		IsActive: w.IsActive,
		Latitude: w.Latitude, Longitude: w.Longitude,
	})
	if err != nil {
		return err
	}
	w.ID = id
	return nil
}

func (r *Repository) Update(ctx context.Context, w *db.Warehouse) error {
	n, err := r.q.UpdateWarehouse(ctx, db.UpdateWarehouseParams{
		ID:       w.ID,
		Name:     w.Name,
		Address:  w.Address,
		IsActive: w.IsActive,
		Latitude: w.Latitude, Longitude: w.Longitude,
	})
	if err != nil {
		return err
	}
	if n == 0 {
		return ErrNotFound
	}
	return nil
}

func (r *Repository) Delete(ctx context.Context, id int64) error {
	n, err := r.q.DeleteWarehouse(ctx, id)
	if err != nil {
		return err
	}
	if n == 0 {
		return ErrNotFound
	}
	return nil
}
