package main

import (
	// External
	we "git.gibonuddevalla.se/go/wrappederror"

	// Standard
	"database/sql"
	"encoding/json"
	"time"
)

type Problem struct {
	ID           int
	Start        time.Time
	End          sql.NullTime
	Acknowledged bool
	TriggerID    int    `json:"trigger_id"`
	TriggerName  string `json:"trigger_name"`
	AreaName     string `json:"area_name"`
	SectionName  string `json:"section_name"`
}

func ProblemsRetrieve() (problems []Problem, err error) {
	problems = []Problem{}
	row := service.Db.Conn.QueryRow(`
		SELECT
			jsonb_agg(problems.*)
		FROM (
			(SELECT
				p.id,
				p.start,
				p.end,
				p.acknowledged,
				t.id   AS trigger_id,
				t.name AS trigger_name,
				a.name AS area_name,
				s.name AS section_name
			FROM problem p
			INNER JOIN "trigger" t ON p.trigger_id = t.id
			INNER JOIN section s ON t.section_id = s.id
			INNER JOIN area a ON s.area_id = a.id
			WHERE
				p.end IS NULL
			ORDER BY
				p.start DESC)

			UNION ALL
			
			(SELECT
				-1 AS id,
				null,
				null,
				false,
				-1 AS trigger_id,
				CONCAT(
					'NODATA: ',
					dp.name
				) AS trigger_name,
				'[NODATA]' AS area_name,
				'[NODATA]' AS section_name
			FROM datapoint dp
			WHERE
				dp.nodata_is_problem
			ORDER BY
				dp.name ASC)
		) AS problems
	`)

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

	if jsonBody == nil {
		return
	}

	err = json.Unmarshal(jsonBody, &problems)
	if err != nil {
		err = we.Wrap(err)
	}
	return
}

func ProblemStart(trigger Trigger) (problemID int, err error) {
	row := service.Db.Conn.QueryRow(`
		SELECT COUNT(id)
		FROM problem
		WHERE
			trigger_id = $1 AND
			"end" IS NULL
		GROUP BY trigger_id
		`,
		trigger.ID,
	)
	var openProblems int
	err = row.Scan(&openProblems)
	if err != nil && err != sql.ErrNoRows {
		err = we.Wrap(err).WithData(trigger.ID)
		return
	}

	// Open up a new problem if no open exists.
	if openProblems == 0 {
		row = service.Db.Conn.QueryRow(`INSERT INTO problem(trigger_id) VALUES($1) RETURNING id`, trigger.ID)
		err = row.Scan(&problemID)
		if err != nil {
			err = we.Wrap(err).WithData(trigger)
		}
	}
	return
}

func ProblemClose(trigger Trigger) (problemID int, err error) {
	row := service.Db.Conn.QueryRow(`UPDATE problem SET "end"=NOW() WHERE trigger_id=$1 AND "end" IS NULL RETURNING id`, trigger.ID)
	err = row.Scan(&problemID)

	if err == sql.ErrNoRows {
		err = nil
		return
	}

	if err != nil {
		err = we.Wrap(err).WithData(trigger)
		return
	}
	return
}

func ProblemAcknowledge(id int, state bool) (err error) {
	_, err = service.Db.Conn.Exec(`UPDATE problem SET "acknowledged"=$2 WHERE id=$1`, id, state)
	if err != nil {
		err = we.Wrap(err).WithData(id)
		return
	}
	return
}
