package models

import (
	"bytes"
	"database/sql"
	"errors"

	"brainminder.speedtech.it/internal/database"
)

type QuicknoteModel struct {
	*BaseModel
}

type Quicknote struct {
	Id           int64  `db:"id"`
	Note         string `db:"note"`
	NoteRendered string `db:"note_rendered"`
}

func (model *QuicknoteModel) One(id int64) (*Quicknote, bool, error) {
	ctx, cancel := database.GetContext()
	defer cancel()

	var row Quicknote

	query := `SELECT * FROM bm_quicknote WHERE id = $1`

	err := model.DB.GetContext(ctx, &row, query, id)
	if errors.Is(err, sql.ErrNoRows) {
		return nil, false, nil
	}

	return &row, true, err
}

func (model *QuicknoteModel) All() ([]Quicknote, bool, error) {
	ctx, cancel := database.GetContext()
	defer cancel()

	query := `SELECT * FROM bm_quicknote ORDER BY note`

	var rows []Quicknote

	err := model.DB.SelectContext(ctx, &rows, query)
	if errors.Is(err, sql.ErrNoRows) {
		return nil, false, nil
	}

	return rows, true, err
}

func (model *QuicknoteModel) Count() int64 {
	ctx, cancel := database.GetContext()
	defer cancel()

	var count int64
	model.DB.GetContext(ctx, &count, "SELECT COUNT(*) FROM bm_quicknote")

	return count
}

func (model *QuicknoteModel) AllQB(offset int64) ([]Quicknote, bool, error) {
	ctx, cancel := database.GetContext()
	defer cancel()

	query := `SELECT * FROM bm_quicknote ORDER BY id DESC LIMIT 10 OFFSET ?`

	var rows []Quicknote

	err := model.DB.SelectContext(ctx, &rows, query, offset)
	if errors.Is(err, sql.ErrNoRows) {
		return nil, false, nil
	}

	rowsLen := len(rows)
	var reversedRows []Quicknote

	for i := range rows {
		reversedRows = append(reversedRows, rows[rowsLen-i-1])
	}

	return reversedRows, true, err
}

func (model *QuicknoteModel) Find(criteria map[string]any) ([]Quicknote, bool, error) {
	ctx, cancel := database.GetContext()
	defer cancel()

	var params []interface{}
	var conditions []string
	var cond string
	query := "SELECT bmq.* FROM bm_quicknote bmq "

	for field, value := range criteria {
		switch field {
		case "Note":
			valstr := value.(string)
			if len(valstr) > 0 {
				params = append(params, valstr)
				conditions = append(conditions, "bmq.note LIKE '%' || ? || '%'")
			}
		}
	}

	for _, condition := range conditions {
		if len(cond) > 0 {
			cond = cond + " AND "
		}
		cond = cond + condition
	}

	if len(cond) > 0 {
		query = query + "WHERE " + cond + " "
	}
	query = query + `ORDER BY bmq.note`

	var rows []Quicknote

	err := model.DB.SelectContext(ctx, &rows, query, params...)
	if errors.Is(err, sql.ErrNoRows) {
		return nil, false, nil
	}

	return rows, true, err
}

func (model *QuicknoteModel) Create(Quicknote *Quicknote) (int64, error) {
	ctx, cancel := database.GetContext()
	defer cancel()

	markdown := *model.GetMarkdown()

	var bufNote bytes.Buffer
	markdown.Convert([]byte(Quicknote.Note), &bufNote)
	Quicknote.NoteRendered = bufNote.String()

	query := `INSERT INTO bm_quicknote (note, note_rendered) VALUES (:note, :note_rendered)`

	result, err := model.DB.NamedExecContext(ctx, query, Quicknote)
	if err != nil {
		return 0, err
	}

	id, err := result.LastInsertId()
	if err != nil {
		return 0, err
	}

	return id, err
}

func (model *QuicknoteModel) Update(Quicknote *Quicknote) error {
	ctx, cancel := database.GetContext()
	defer cancel()

	markdown := *model.GetMarkdown()

	var bufNote bytes.Buffer
	markdown.Convert([]byte(Quicknote.Note), &bufNote)
	Quicknote.NoteRendered = bufNote.String()

	query := `UPDATE bm_quicknote SET note=:note, note_rendered=:note_rendered WHERE id = :id`

	_, err := model.DB.NamedExecContext(ctx, query, Quicknote)

	return err
}

func (model *QuicknoteModel) Delete(id int64) (bool, error) {
	ctx, cancel := database.GetContext()
	defer cancel()

	query := `DELETE FROM bm_quicknote WHERE id = $1`

	_, err := model.DB.ExecContext(ctx, query, id)
	if errors.Is(err, sql.ErrNoRows) {
		return false, nil
	}

	return true, err
}