'use strict';

module.exports = function (module) {
	var helpers = require('./helpers');

	module.listPrepend = async function (key, value) {
		if (!key) {
			return;
		}

		await module.transaction(async function (client) {
			await helpers.ensureLegacyObjectType(client, key, 'list');
			await client.query({
				name: 'listPrepend',
				text: `
INSERT INTO "legacy_list" ("_key", "array")
VALUES ($1::TEXT, ARRAY[$2::TEXT])
ON CONFLICT ("_key")
DO UPDATE SET "array" = ARRAY[$2::TEXT] || "legacy_list"."array"`,
				values: [key, value],
			});
		});
	};

	module.listAppend = async function (key, value) {
		if (!key) {
			return;
		}

		await module.transaction(async function (client) {
			await helpers.ensureLegacyObjectType(client, key, 'list');
			await client.query({
				name: 'listAppend',
				text: `
INSERT INTO "legacy_list" ("_key", "array")
VALUES ($1::TEXT, ARRAY[$2::TEXT])
ON CONFLICT ("_key")
DO UPDATE SET "array" = "legacy_list"."array" || ARRAY[$2::TEXT]`,
				values: [key, value],
			});
		});
	};

	module.listRemoveLast = async function (key) {
		if (!key) {
			return;
		}

		const res = await module.pool.query({
			name: 'listRemoveLast',
			text: `
WITH A AS (
	SELECT l.*
	  FROM "legacy_object_live" o
	 INNER JOIN "legacy_list" l
	         ON o."_key" = l."_key"
	        AND o."type" = l."type"
	 WHERE o."_key" = $1::TEXT
	   FOR UPDATE)
UPDATE "legacy_list" l
   SET "array" = A."array"[1 : array_length(A."array", 1) - 1]
  FROM A
 WHERE A."_key" = l."_key"
RETURNING A."array"[array_length(A."array", 1)] v`,
			values: [key],
		});

		return res.rows.length ? res.rows[0].v : null;
	};

	module.listRemoveAll = async function (key, value) {
		if (!key) {
			return;
		}

		await module.pool.query({
			name: 'listRemoveAll',
			text: `
UPDATE "legacy_list" l
   SET "array" = array_remove(l."array", $2::TEXT)
  FROM "legacy_object_live" o
 WHERE o."_key" = l."_key"
   AND o."type" = l."type"
   AND o."_key" = $1::TEXT`,
			values: [key, value],
		});
	};

	module.listTrim = async function (key, start, stop) {
		if (!key) {
			return;
		}

		stop += 1;

		await module.pool.query(stop > 0 ? {
			name: 'listTrim',
			text: `
UPDATE "legacy_list" l
   SET "array" = ARRAY(SELECT m.m
                         FROM UNNEST(l."array") WITH ORDINALITY m(m, i)
                        ORDER BY m.i ASC
                        LIMIT ($3::INTEGER - $2::INTEGER)
                       OFFSET $2::INTEGER)
  FROM "legacy_object_live" o
 WHERE o."_key" = l."_key"
   AND o."type" = l."type"
   AND o."_key" = $1::TEXT`,
			values: [key, start, stop],
		} : {
			name: 'listTrimBack',
			text: `
UPDATE "legacy_list" l
   SET "array" = ARRAY(SELECT m.m
                         FROM UNNEST(l."array") WITH ORDINALITY m(m, i)
                        ORDER BY m.i ASC
                        LIMIT ($3::INTEGER - $2::INTEGER + array_length(l."array", 1))
                       OFFSET $2::INTEGER)
  FROM "legacy_object_live" o
 WHERE o."_key" = l."_key"
   AND o."type" = l."type"
   AND o."_key" = $1::TEXT`,
			values: [key, start, stop],
		});
	};

	module.getListRange = async function (key, start, stop) {
		if (!key) {
			return;
		}

		stop += 1;

		const res = await module.pool.query(stop > 0 ? {
			name: 'getListRange',
			text: `
SELECT ARRAY(SELECT m.m
               FROM UNNEST(l."array") WITH ORDINALITY m(m, i)
              ORDER BY m.i ASC
              LIMIT ($3::INTEGER - $2::INTEGER)
             OFFSET $2::INTEGER) l
  FROM "legacy_object_live" o
 INNER JOIN "legacy_list" l
         ON o."_key" = l."_key"
        AND o."type" = l."type"
      WHERE o."_key" = $1::TEXT`,
			values: [key, start, stop],
		} : {
			name: 'getListRangeBack',
			text: `
SELECT ARRAY(SELECT m.m
               FROM UNNEST(l."array") WITH ORDINALITY m(m, i)
              ORDER BY m.i ASC
              LIMIT ($3::INTEGER - $2::INTEGER + array_length(l."array", 1))
             OFFSET $2::INTEGER) l
  FROM "legacy_object_live" o
 INNER JOIN "legacy_list" l
         ON o."_key" = l."_key"
        AND o."type" = l."type"
 WHERE o."_key" = $1::TEXT`,
			values: [key, start, stop],
		});

		return res.rows.length ? res.rows[0].l : [];
	};

	module.listLength = async function (key) {
		const res = await module.pool.query({
			name: 'listLength',
			text: `
SELECT array_length(l."array", 1) l
  FROM "legacy_object_live" o
 INNER JOIN "legacy_list" l
         ON o."_key" = l."_key"
        AND o."type" = l."type"
      WHERE o."_key" = $1::TEXT`,
			values: [key],
		});

		return res.rows.length ? res.rows[0].l : 0;
	};
};
