-- name: migration-0000-create-jobs#
CREATE TABLE IF NOT EXISTS job_statuses (
   id INTEGER PRIMARY KEY AUTOINCREMENT
 , name TEXT
 , UNIQUE(name)
);

INSERT OR IGNORE INTO job_statuses (id, name) VALUES (2, 'success');
INSERT OR IGNORE INTO job_statuses (id, name) VALUES (1, 'running');
INSERT OR IGNORE INTO job_statuses (id, name) VALUES (0, 'queued');
INSERT OR IGNORE INTO job_statuses (id, name) VALUES (-1, 'cancelled');
INSERT OR IGNORE INTO job_statuses (id, name) VALUES (-2, 'failed');

CREATE TABLE IF NOT EXISTS jobs (
   id INTEGER PRIMARY KEY AUTOINCREMENT
 , user_id INTEGER NOT NULL
 , file_id INTEGER NOT NULL
 , printer_id INTEGER
 , started_at TEXT
 , cancelled_at TEXT
 , finished_at TEXT
 , status_id INTEGER DEFAULT (0)
 , message TEXT
 , FOREIGN KEY(user_id) REFERENCES users(id)
 , FOREIGN KEY(file_id) REFERENCES files(id)
 , FOREIGN KEY(printer_id) REFERENCES printer(id)
);

-- name: create-job^
INSERT INTO jobs (
   user_id
 , file_id
)
VALUES (
   :uid
 , :fid
)
RETURNING
   id
;
-- name: fetch-job^
SELECT
   *
FROM jobs
WHERE
   user_id = :uid
   AND id = :jid
;

-- name: list-jobs
SELECT
   *
 , (SELECT name FROM job_statuses WHERE id = j.status_id) AS `status`
FROM jobs
WHERE
   (:uid IS NULL OR user_id = :uid)
;

-- name: list-jobs-by-file
SELECT
   finished_at
 , (SELECT name FROM job_statuses WHERE id = j.status_id) AS `status`
FROM jobs j
WHERE
   file_id = :fid
   AND user_id = :uid
;

-- name: list-job-queue
SELECT
   j.id as id
 , j.file_id
 , fa.id as analysis_id
 , fa.max_x
 , fa.max_y
 , fa.max_z
 , fa.max_bed
 , fa.max_end
 , fa.nozzle_diameter
 , fa.filament_id
 , (SELECT name FROM filament WHERE id = fa.filament_id) AS filament_name
 , (SELECT name FROM job_statuses WHERE id = j.status_id) AS status
 , j.started_at
 , j.cancelled_at
 , j.finished_at
 , j.user_id
 , j.printer_id
FROM jobs j
INNER JOIN files f
  ON j.file_id = f.id
LEFT JOIN file_analysis fa
  ON fa.file_id = f.id
WHERE
   finished_at IS NULL
   AND cancelled_at IS NULL
   AND (:uid IS NULL OR j.user_id = :uid)
   AND f.id IS NOT NULL
;

-- name: poll-job-queue^
SELECT
   *
FROM jobs
WHERE
   started_at IS NULL
   AND finished_at IS NULL
   AND printer_id IS NULL
LIMIT 1
;

-- name: list-job-history
SELECT
   j.*
 , fa.id as analysis_id
 , (SELECT name FROM job_statuses WHERE id = j.status_id) AS `status`
FROM jobs j
INNER JOIN files f
  ON j.file_id = f.id
LEFT JOIN file_analysis fa
  ON fa.file_id = f.id
WHERE
   finished_at IS NOT NULL
   AND (:uid IS NULL OR j.user_id = :uid)
ORDER BY
   datetime(finished_at) DESC
LIMIT 25
;

-- name: list-mapped-jobs
SELECT
   *
FROM jobs
WHERE
   started_at IS NULL
   AND printer_id IS NOT NULL
;

-- name: list-running-jobs
SELECT
   *
FROM jobs
WHERE
   started_at IS NOT NULL
   AND printer_id IS NOT NULL
   AND finished_at IS NULL
;

-- name: list-canceling-jobs
SELECT
   *
FROM jobs
WHERE
   finished_at IS NULL
   AND cancelled_at IS NOT NULL
;

-- name: fetch-job-by-printer^
SELECT
   *
FROM jobs
WHERE
   printer_id = :pid
   AND finished_at IS NULL
;

-- name: assign-job!
UPDATE jobs
SET
   printer_id = :pid
WHERE
   id = :jid
;

-- name: start-job!
UPDATE jobs
SET
   started_at = datetime('now')
WHERE
   id = :jid
   AND started_at IS NULL
;

-- name: cancel-job!
UPDATE jobs
SET
   cancelled_at = datetime('now')
WHERE
   (:uid IS NULL OR user_id = :uid)
   AND id = :jid
;

-- name: finish-job!
UPDATE jobs
SET
   finished_at = datetime('now')
 , status_id = (SELECT id FROM job_statuses WHERE name = :state)
 , message = :message
WHERE
   id = :jid
   AND finished_at IS NULL -- guard against calling this twice
;

-- name: delete-job!
DELETE FROM jobs
WHERE
   user_id = :uid
   AND id = :jid
;

-- name: delete-jobs-by-fid!
DELETE FROM jobs
WHERE
   (:uid IS NULL OR user_id = :uid)
   AND file_id = :fid
;

-- name: update-job-status!
UPDATE jobs
   SET status_id = (SELECT id FROM job_statuses WHERE name = :status)
WHERE
   id = :jid
;
