package comercios

import (
	"database/sql"
)

// Comercio representa un comercio (supermercado) donde se realizan las compras.
type Comercio struct {
	Id     int    `json:"id"`
	Nombre string `json:"nombre"`
}

type DataWrapper struct {
	Comercios []Comercio `json:"comercios"`
}

// CrearTabla crea la tabla de comercios si todavía no existe.
func CrearTabla(db *sql.DB) error {

	sentencia := `CREATE TABLE IF NOT EXISTS comercios (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		nombre TEXT NOT NULL UNIQUE
	);`

	if _, err := db.Exec(sentencia); err != nil {

		return err

	}

	return nil
}

// InsertarComercio añade un nuevo comercio y devuelve su identificador.
func InsertarComercio(db *sql.DB, c *Comercio) (int64, error) {

	resultado, err := db.Exec(`INSERT INTO comercios (nombre) VALUES (?);`, c.Nombre)
	if err != nil {

		return 0, err

	}

	return resultado.LastInsertId()
}

// ObtenerComercios devuelve todos los comercios ordenados por nombre.
func ObtenerComercios(db *sql.DB) ([]Comercio, error) {

	filas, err := db.Query(`SELECT id, nombre FROM comercios ORDER BY nombre;`)
	if err != nil {

		return nil, err

	}
	defer filas.Close()

	comercios := []Comercio{}

	for filas.Next() {

		var c Comercio
		if err := filas.Scan(&c.Id, &c.Nombre); err != nil {

			return nil, err

		}

		comercios = append(comercios, c)

	}

	return comercios, filas.Err()
}

// ObtenerComerciosConProductos devuelve únicamente los comercios que tienen
// al menos un producto asociado en la tabla productos.
func ObtenerComerciosConProductos(db *sql.DB) ([]Comercio, error) {

	filas, err := db.Query(`SELECT c.id, c.nombre
		FROM comercios c
		WHERE EXISTS (
			SELECT 1
			FROM productos p
			WHERE UPPER(TRIM(p.comercio)) = UPPER(TRIM(c.nombre))
		)
		ORDER BY c.nombre;`)
	if err != nil {

		return nil, err

	}
	defer filas.Close()

	comercios := []Comercio{}

	for filas.Next() {

		var c Comercio
		if err := filas.Scan(&c.Id, &c.Nombre); err != nil {

			return nil, err

		}

		comercios = append(comercios, c)

	}

	return comercios, filas.Err()
}

// ObtenerComercio devuelve un comercio por su identificador.
// Si no existe, devuelve nil y error nulo.
func ObtenerComercio(db *sql.DB, id int) (*Comercio, error) {

	var c Comercio

	err := db.QueryRow(`SELECT id, nombre FROM comercios WHERE id = ?;`, id).
		Scan(&c.Id, &c.Nombre)

	if err == sql.ErrNoRows {

		return nil, nil

	}

	if err != nil {

		return nil, err

	}

	return &c, nil
}

// ActualizarComercio modifica el nombre de un comercio existente.
func ActualizarComercio(db *sql.DB, id int, nombre string) (int64, error) {

	resultado, err := db.Exec(`UPDATE comercios SET nombre = ? WHERE id = ?;`, nombre, id)
	if err != nil {

		return 0, err

	}

	return resultado.RowsAffected()
}

// EliminarComercio borra un comercio por su identificador.
func EliminarComercio(db *sql.DB, id int) (int64, error) {

	resultado, err := db.Exec(`DELETE FROM comercios WHERE id = ?;`, id)
	if err != nil {

		return 0, err

	}

	return resultado.RowsAffected()
}
