package main

import (
	// External
	werr "git.ahall.se/go/wrappederror"
	"github.com/jackc/pgx/v5"

	// Standard
	"context"
	"encoding/json"
	"sort"
)

type Area struct {
	ID   int
	Name string

	Sections []Section
}

func AreaRetrieve() (areas []Area, err error) { // {{{
	areas = []Area{}
	row := db.QueryRow(context.Background(), `
		SELECT
			 jsonb_agg(jsonsections)
		FROM (
			SELECT
				a.id,
				a.name,
				jsonb_agg(
					jsonb_build_object(
						'id', s.id,
						'name', s.name
					)
				) AS sections
			FROM area a
			LEFT JOIN section s ON s.area_id = a.id
			GROUP BY
				a.id, a.name
		) jsonsections`,
	)

	var jsonData []byte
	err = row.Scan(&jsonData)
	if err != nil {
		err = werr.Wrap(err)
		return
	}

	if jsonData == nil {
		return
	}

	err = json.Unmarshal(jsonData, &areas)
	if err != nil {
		err = werr.Wrap(err)
		return
	}

	return
} // }}}
func AreaCreate(name string) (err error) { // {{{
	_, err = db.Exec(context.Background(), `INSERT INTO area(name) VALUES($1)`, name)
	return
} // }}}
func AreaRename(id int, name string) (err error) { // {{{
	_, err = db.Exec(context.Background(), `UPDATE area SET name=$2 WHERE id=$1`, id, name)
	return
} // }}}
func AreaDelete(id int) (err error) { // {{{
	ctx := context.Background()

	var trx pgx.Tx
	trx, err = db.Begin(ctx)
	if err != nil {
		err = werr.Wrap(err).WithData(id)
	}

	_, err = trx.Exec(context.Background(), `
		DELETE
		FROM trigger t
		USING section s
		WHERE
			t.section_id = s.id AND
			s.area_id = $1
		`,
		id,
	)
	if err != nil {
		err2 := trx.Rollback(ctx)
		if err2 != nil {
			return werr.Wrap(err2).WithData(err)
		}
		return werr.Wrap(err).WithData(id)
	}

	_, err = trx.Exec(ctx, `DELETE FROM public.section WHERE area_id = $1`, id)
	if err != nil {
		err2 := trx.Rollback(ctx)
		if err2 != nil {
			return werr.Wrap(err2).WithData(err)
		}
		return werr.Wrap(err).WithData(id)
	}

	_, err = trx.Exec(ctx, `DELETE FROM public.area WHERE id = $1`, id)
	if err != nil {
		err2 := trx.Rollback(ctx)
		if err2 != nil {
			return werr.Wrap(err2).WithData(err)
		}
		return werr.Wrap(err).WithData(id)
	}

	err = trx.Commit(ctx)
	if err != nil {
		err2 := trx.Rollback(ctx)
		if err2 != nil {
			return werr.Wrap(err2).WithData(err)
		}
		return werr.Wrap(err).WithData(id)
	}

	return nil
} // }}}

func (a Area) SortedSections() []Section { // {{{
	sort.SliceStable(a.Sections, func(i, j int) bool {
		return a.Sections[i].Name < a.Sections[j].Name
	})
	return a.Sections
} // }}}
