CREATE DATABASE financial_data;

DO $$
BEGIN
	IF NOT EXISTS (
		SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = 'financial_user'
	) THEN
		CREATE ROLE financial_user LOGIN PASSWORD 'securepassword';
	END IF;
END
$$;

GRANT ALL PRIVILEGES ON DATABASE financial_data TO financial_user;

CREATE TABLE IF NOT EXISTS organizations(
id SERIAL PRIMARY KEY,
orgname VARCHAR(50) UNIQUE NOT NULL
);

CREATE TABLE IF NOT EXISTS accounts(
id SERIAL PRIMARY KEY,
accountnum VARCHAR UNIQUE NOT NULL,
accountname VARCHAR UNIQUE NOT NULL,
orgid INT REFERENCES organizations(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS vendors(
id SERIAL PRIMARY KEY,
vendorname VARCHAR NOT NULL,
orgid INT REFERENCES organizations(id) ON DELETE RESTRICT
);

-- how can I normalize this further? going to end up with lots of nulls in the transactions table, but not sure if it's worth it to have separate tables for each transaction type (e.g. fund transactions, card transactions, etc.)
CREATE TABLE IF NOT EXISTS transactions(
id SERIAL PRIMARY KEY,
datetime DATE NOT NULL,
description VARCHAR NOT NULL,
amount REAL NOT NULL,
accountid INT REFERENCES accounts(id) ON DELETE RESTRICT,
orgid INT REFERENCES organizations(id) ON DELETE RESTRICT,
vendorid INT REFERENCES vendors(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS snapshots(
id SERIAL PRIMARY KEY,
datetime DATE NOT NULL,
accountid INT REFERENCES accounts(id) ON DELETE RESTRICT,
balance REAL NOT NULL,
orgid INT REFERENCES organizations(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS syncs(
id SERIAL PRIMARY KEY,
datetime DATE NOT NULL,
accountid INT REFERENCES accounts(id) ON DELETE RESTRICT,
orgid INT REFERENCES organizations(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS rawtransactions(
id SERIAL PRIMARY KEY,
data JSONB NOT NULL,
received_at TIMESTAMPTZ NOT NULL DEFAULT now(),
source VARCHAR(100),
accountid INT REFERENCES accounts(id) ON DELETE RESTRICT,
orgid INT REFERENCES organizations(id) ON DELETE RESTRICT,
raw_sha256 CHAR(64) UNIQUE,
processed BOOLEAN NOT NULL DEFAULT FALSE
);

CREATE TABLE IF NOT EXISTS currency(
id SERIAL PRIMARY KEY,
currencycode CHAR(3) UNIQUE NOT NULL,
currencyname VARCHAR(50) NOT NULL
);

CREATE TABLE IF NOT EXISTS funds(
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
datetime DATE NOT NULL,
amount REAL NOT NULL,
accountid INT REFERENCES accounts(id) ON DELETE RESTRICT,
orgid INT REFERENCES organizations(id) ON DELETE RESTRICT,
fundid VARCHAR(100) NOT NULL,
value REAL NOT NULL,
shares REAL NOT NULL,
currencyid INT REFERENCES currency(id) ON DELETE RESTRICT
);

--assets, liabilities, equity, income, expenses
CREATE TABLE IF NOT EXISTS accounttypes(
id SERIAL PRIMARY KEY,
typename VARCHAR(100) NOT NULL,
includeinnetworth BOOLEAN NOT NULL
);

CREATE INDEX IF NOT EXISTS rawtransactions_data_idx ON rawtransactions USING GIN (data);
CREATE INDEX IF NOT EXISTS rawtransactions_received_at_idx ON rawtransactions (received_at);
CREATE INDEX IF NOT EXISTS rawtransactions_account_org_idx ON rawtransactions (orgid, accountid);

CREATE INDEX IF NOT EXISTS accounts_orgid_idx ON accounts (orgid);
CREATE INDEX IF NOT EXISTS vendors_orgid_idx ON vendors (orgid);

CREATE INDEX IF NOT EXISTS transactions_accountid_idx ON transactions (accountid);
CREATE INDEX IF NOT EXISTS transactions_orgid_idx ON transactions (orgid);
CREATE INDEX IF NOT EXISTS transactions_vendorid_idx ON transactions (vendorid);
CREATE INDEX IF NOT EXISTS transactions_account_datetime_idx ON transactions (accountid, datetime);
CREATE INDEX IF NOT EXISTS transactions_org_datetime_idx ON transactions (orgid, datetime);

CREATE INDEX IF NOT EXISTS snapshots_accountid_idx ON snapshots (accountid);
CREATE INDEX IF NOT EXISTS snapshots_orgid_idx ON snapshots (orgid);
CREATE INDEX IF NOT EXISTS snapshots_account_datetime_idx ON snapshots (accountid, datetime);
CREATE INDEX IF NOT EXISTS snapshots_org_datetime_idx ON snapshots (orgid, datetime);

CREATE INDEX IF NOT EXISTS syncs_accountid_idx ON syncs (accountid);
CREATE INDEX IF NOT EXISTS syncs_orgid_idx ON syncs (orgid);
CREATE INDEX IF NOT EXISTS syncs_account_datetime_idx ON syncs (accountid, datetime);
CREATE INDEX IF NOT EXISTS syncs_org_datetime_idx ON syncs (orgid, datetime);

CREATE INDEX IF NOT EXISTS rawtransactions_accountid_idx ON rawtransactions (accountid);
CREATE INDEX IF NOT EXISTS rawtransactions_orgid_idx ON rawtransactions (orgid);

CREATE INDEX IF NOT EXISTS funds_accountid_idx ON funds (accountid);
CREATE INDEX IF NOT EXISTS funds_orgid_idx ON funds (orgid);
CREATE INDEX IF NOT EXISTS funds_currencyid_idx ON funds (currencyid);
CREATE INDEX IF NOT EXISTS funds_account_datetime_idx ON funds (accountid, datetime);
CREATE INDEX IF NOT EXISTS funds_org_datetime_idx ON funds (orgid, datetime);