-- This schema is included at compile-time into
-- source/profile/data_impl_sqlite.d SqliteProfileDataSource
-- ----------------------------------------------------------------------------
-- This is the full current schema for Finnow's database. Tables and statements
-- are defined in the order in which they're executed to build a new database
-- for a newly-created profile.

-- Basic/Utility Entities

CREATE TABLE profile_property (
    property TEXT PRIMARY KEY,
    value TEXT DEFAULT NULL
);

CREATE TABLE attachment (
    id INTEGER PRIMARY KEY,
    uploaded_at TEXT NOT NULL,
    filename TEXT NOT NULL,
    content_type TEXT NOT NULL,
    size INTEGER NOT NULL,
    content BLOB NOT NULL
);

-- Account Entities

CREATE TABLE account (
    id INTEGER PRIMARY KEY,
    created_at TEXT NOT NULL,
    archived BOOLEAN NOT NULL DEFAULT FALSE,
    type TEXT NOT NULL,
    number_suffix TEXT,
    name TEXT NOT NULL,
    currency TEXT NOT NULL,
    description TEXT
);

CREATE TABLE account_credit_card_properties (
    account_id INTEGER PRIMARY KEY,
    credit_limit INTEGER,
    CONSTRAINT fk_account_credit_card_properties_account
        FOREIGN KEY (account_id) REFERENCES account(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

-- Transaction Entities

CREATE TABLE transaction_vendor (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL UNIQUE,
    description TEXT
);

CREATE TABLE transaction_category (
    id INTEGER PRIMARY KEY,
    parent_id INTEGER,
    name TEXT NOT NULL UNIQUE,
    description TEXT,
    color TEXT NOT NULL DEFAULT 'FFFFFF',
    CONSTRAINT fk_transaction_category_parent
        FOREIGN KEY (parent_id) REFERENCES transaction_category(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

CREATE TABLE "transaction" (
    id INTEGER PRIMARY KEY,
    timestamp TEXT NOT NULL,
    added_at TEXT NOT NULL,
    amount INTEGER NOT NULL,
    currency TEXT NOT NULL,
    description TEXT,
    internal_transfer BOOLEAN NOT NULL DEFAULT FALSE,
    vendor_id INTEGER,
    category_id INTEGER,
    CONSTRAINT fk_transaction_vendor
        FOREIGN KEY (vendor_id) REFERENCES transaction_vendor(id)
            ON UPDATE CASCADE ON DELETE SET NULL,
    CONSTRAINT fk_transaction_category
        FOREIGN KEY (category_id) REFERENCES transaction_category(id)
            ON UPDATE CASCADE ON DELETE SET NULL,
    CONSTRAINT ck_transaction_amount_positive
        CHECK (amount > 0)
);
CREATE INDEX idx_transaction_by_timestamp ON "transaction"(timestamp);

CREATE TABLE transaction_tag (
    transaction_id INTEGER NOT NULL,
    tag TEXT NOT NULL,
    CONSTRAINT pk_transaction_tag PRIMARY KEY (transaction_id, tag),
    CONSTRAINT fk_transaction_tag_transaction
        FOREIGN KEY (transaction_id) REFERENCES "transaction"(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

CREATE TABLE transaction_attachment (
    transaction_id INTEGER NOT NULL,
    attachment_id INTEGER NOT NULL,
    PRIMARY KEY (transaction_id, attachment_id),
    CONSTRAINT fk_transaction_attachment_transaction
        FOREIGN KEY (transaction_id) REFERENCES "transaction"(id)
            ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_transaction_attachment_attachment
        FOREIGN KEY (attachment_id) REFERENCES attachment(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

CREATE TABLE transaction_line_item (
    transaction_id INTEGER NOT NULL,
    idx INTEGER NOT NULL DEFAULT 0,
    value_per_item INTEGER NOT NULL,
    quantity INTEGER NOT NULL DEFAULT 1,
    description TEXT NOT NULL,
    category_id INTEGER,
    CONSTRAINT pk_transaction_line_item PRIMARY KEY (transaction_id, idx),
    CONSTRAINT fk_transaction_line_item_transaction
        FOREIGN KEY (transaction_id) REFERENCES "transaction"(id)
            ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_transaction_line_item_category
        FOREIGN KEY (category_id) REFERENCES transaction_category(id)
            ON UPDATE CASCADE ON DELETE SET NULL
);

CREATE TABLE account_journal_entry (
    id INTEGER PRIMARY KEY,
    timestamp TEXT NOT NULL,
    account_id INTEGER NOT NULL,
    transaction_id INTEGER NOT NULL,
    amount INTEGER NOT NULL,
    type TEXT NOT NULL,
    currency TEXT NOT NULL,
    CONSTRAINT fk_account_journal_entry_account
        FOREIGN KEY (account_id) REFERENCES account(id)
            ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_account_journal_entry_transaction
        FOREIGN KEY (transaction_id) REFERENCES "transaction"(id)
            ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT uq_account_journal_entry_ids
        UNIQUE (account_id, transaction_id),
    CONSTRAINT ck_account_journal_entry_amount_positive
        CHECK (amount > 0)
);

-- Value records

CREATE TABLE account_value_record (
    id INTEGER PRIMARY KEY,
    timestamp TEXT NOT NULL,
    account_id INTEGER NOT NULL,
    type TEXT NOT NULL DEFAULT 'BALANCE',
    value INTEGER NOT NULL,
    currency TEXT NOT NULL,
    CONSTRAINT fk_account_value_record_account
        FOREIGN KEY (account_id) REFERENCES account(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

CREATE TABLE account_value_record_attachment (
    value_record_id INTEGER NOT NULL,
    attachment_id INTEGER NOT NULL,
    PRIMARY KEY (value_record_id, attachment_id),
    CONSTRAINT fk_account_value_record_attachment_value_record
        FOREIGN KEY (value_record_id) REFERENCES account_value_record(id)
            ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_account_value_record_attachment_attachment
        FOREIGN KEY (attachment_id) REFERENCES attachment(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

-- History Entities

CREATE TABLE account_history_item (
    id INTEGER PRIMARY KEY,
    account_id INTEGER NOT NULL,
    timestamp TEXT NOT NULL,
    type TEXT NOT NULL,
    CONSTRAINT fk_account_history_item_account
        FOREIGN KEY (account_id) REFERENCES account(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

-- A plain text history item.
CREATE TABLE history_item_text (
    item_id INTEGER PRIMARY KEY,
    content TEXT NOT NULL,
    CONSTRAINT fk_history_item_text_item
        FOREIGN KEY (item_id) REFERENCES account_history_item(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

-- Zero or more property changes may be logged for a history item.
CREATE TABLE history_item_property_change (
    item_id INTEGER NOT NULL,
    property_name TEXT NOT NULL,
    old_value TEXT,
    new_value TEXT,
    PRIMARY KEY (item_id, property_name),
    CONSTRAINT fk_history_item_property_change_item
        FOREIGN KEY (item_id) REFERENCES account_history_item(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

-- Links a value record to a history item, used to include value records in an account's history.
CREATE TABLE history_item_linked_value_record (
    item_id INTEGER NOT NULL,
    value_record_id INTEGER NOT NULL,
    PRIMARY KEY (item_id, value_record_id),
    CONSTRAINT fk_history_item_linked_value_record_item
        FOREIGN KEY (item_id) REFERENCES account_history_item(id)
            ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_history_item_linked_value_record_value_record
        FOREIGN KEY (value_record_id) REFERENCES account_value_record(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

-- Links a journal entry to a history item, used to include journal entries in an account's history.
CREATE TABLE history_item_linked_journal_entry (
    item_id INTEGER NOT NULL,
    journal_entry_id INTEGER NOT NULL,
    PRIMARY KEY (item_id, journal_entry_id),
    CONSTRAINT fk_history_item_linked_journal_entry_item
        FOREIGN KEY (item_id) REFERENCES account_history_item(id)
            ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_history_item_linked_journal_entry_journal_entry
        FOREIGN KEY (journal_entry_id) REFERENCES account_journal_entry(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

-- Drafts / Templates / Recurring Transactions
-- Generally, draft tables are copies of their normal transaction counterparts,
-- with looser nullability constraints in some cases.

CREATE TABLE transaction_draft (
    id INTEGER PRIMARY KEY,
    added_at TEXT NOT NULL,
    template_name TEXT,
    timestamp TEXT,
    amount INTEGER,
    currency TEXT,
    description TEXT,
    internal_transfer BOOLEAN DEFAULT FALSE,
    vendor_id INTEGER,
    category_id INTEGER,
    credited_account_id INTEGER,
    debited_account_id INTEGER,
    CONSTRAINT fk_transaction_draft_vendor
        FOREIGN KEY (vendor_id) REFERENCES transaction_vendor(id)
            ON UPDATE CASCADE ON DELETE SET NULL,
    CONSTRAINT fk_transaction_draft_category
        FOREIGN KEY (category_id) REFERENCES transaction_category(id)
            ON UPDATE CASCADE ON DELETE SET NULL,
    CONSTRAINT fk_transaction_draft_credited_account
        FOREIGN KEY (credited_account_id) REFERENCES account(id)
            ON UPDATE CASCADE ON DELETE SET NULL,
    CONSTRAINT fk_transaction_draft_debited_account
        FOREIGN KEY (debited_account_id) REFERENCES account(id)
            ON UPDATE CASCADE ON DELETE SET NULL,
    CONSTRAINT ck_transaction_amount_positive
        CHECK (amount IS NULL OR amount > 0)
);

CREATE TABLE transaction_draft_tag (
    draft_id INTEGER NOT NULL,
    tag TEXT NOT NULL,
    CONSTRAINT pk_transaction_draft_tag PRIMARY KEY (draft_id, tag),
    CONSTRAINT fk_transaction_draft_tag_draft
        FOREIGN KEY (draft_id) REFERENCES transaction_draft(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

CREATE TABLE transaction_draft_attachment (
    draft_id INTEGER NOT NULL,
    attachment_id INTEGER NOT NULL,
    PRIMARY KEY (draft_id, attachment_id),
    CONSTRAINT fk_transaction_draft_attachment_transaction
        FOREIGN KEY (draft_id) REFERENCES transaction_draft(id)
            ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_transaction_draft_attachment_attachment
        FOREIGN KEY (attachment_id) REFERENCES attachment(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

CREATE TABLE transaction_draft_line_item (
    draft_id INTEGER NOT NULL,
    idx INTEGER NOT NULL DEFAULT 0,
    value_per_item INTEGER NOT NULL,
    quantity INTEGER NOT NULL DEFAULT 1,
    description TEXT NOT NULL,
    category_id INTEGER,
    CONSTRAINT pk_transaction_draft_line_item PRIMARY KEY (draft_id, idx),
    CONSTRAINT fk_transaction_draft_line_item_transaction
        FOREIGN KEY (draft_id) REFERENCES transaction_draft(id)
            ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_transaction_draft_line_item_category
        FOREIGN KEY (category_id) REFERENCES transaction_category(id)
            ON UPDATE CASCADE ON DELETE SET NULL
);

CREATE TABLE recurring_transaction (
    id INTEGER PRIMARY KEY,
    draft_id INTEGER NOT NULL,
    schedule_expr TEXT NOT NULL,
    CONSTRAINT fk_recurring_transaction_draft
        FOREIGN KEY (draft_id) REFERENCES transaction_draft(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);

-- A "queue" table where upcoming recurring transactions are posted until it's
-- time to add them for real. This ensures proper handling of recurring transactions.
CREATE TABLE recurring_transaction_queue (
    recurring_transaction_id INTEGER PRIMARY KEY,
    scheduled_timestamp TEXT NOT NULL,
    CONSTRAINT fk_recurring_transaction_queue_id
        FOREIGN KEY (recurring_transaction_id) REFERENCES recurring_transaction(id)
            ON UPDATE CASCADE ON DELETE CASCADE
);
