-- +goose Up
-- +goose StatementBegin

-- Network interfaces declared by the operator. The kernel-side
-- interfaces (eth0, eth1, ...) appear here via "discovery" — same
-- name as the OS device. VLAN/bond/bridge interfaces are operator-
-- created and the runtime renderer (Phase-3) will translate them
-- into /etc/systemd/network/*.network files.
--
-- role drives where the firewall/HAProxy generators expect this
-- interface to live: 'wan' = public-facing, 'lan' = internal,
-- 'dmz' = quarantined, 'mgmt' = admin-only, 'cluster' = peer-mTLS.
CREATE TABLE IF NOT EXISTS network_interfaces (
    id           BIGSERIAL PRIMARY KEY,
    name         TEXT NOT NULL,
    type         TEXT NOT NULL DEFAULT 'ethernet',
    parent       TEXT,
    vlan_id      INTEGER,
    role         TEXT NOT NULL DEFAULT 'lan',
    mtu          INTEGER,
    active       BOOLEAN NOT NULL DEFAULT TRUE,
    description  TEXT,
    created_at   TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at   TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT network_interfaces_name_unique UNIQUE (name),
    CONSTRAINT network_interfaces_type_check  CHECK (type IN ('ethernet', 'vlan', 'bond', 'bridge', 'wireguard')),
    CONSTRAINT network_interfaces_role_check  CHECK (role IN ('wan', 'lan', 'dmz', 'mgmt', 'cluster')),
    CONSTRAINT network_interfaces_vlan_check  CHECK (
        (type = 'vlan' AND vlan_id BETWEEN 1 AND 4094 AND parent IS NOT NULL)
        OR (type <> 'vlan')
    )
);

CREATE INDEX IF NOT EXISTS idx_network_interfaces_role   ON network_interfaces (role);
CREATE INDEX IF NOT EXISTS idx_network_interfaces_active ON network_interfaces (active) WHERE active;

-- IP addresses bound to a declared interface.
--
-- is_vip flags addresses that should follow the cluster's active
-- node (Phase-3 floating-IP / VRRP-via-hoster-API logic). vip_priority
-- gives the failover preference (higher wins); ignored for non-VIP
-- rows.
--
-- The same address can live on the same interface only once
-- (UNIQUE), but the same address may legitimately appear on
-- different interfaces (e.g. as anycast endpoint).
CREATE TABLE IF NOT EXISTS ip_addresses (
    id            BIGSERIAL PRIMARY KEY,
    interface_id  BIGINT NOT NULL REFERENCES network_interfaces(id) ON DELETE CASCADE,
    address       TEXT NOT NULL,
    prefix        INTEGER NOT NULL,
    is_vip        BOOLEAN NOT NULL DEFAULT FALSE,
    vip_priority  INTEGER,
    description   TEXT,
    active        BOOLEAN NOT NULL DEFAULT TRUE,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT ip_addresses_iface_addr_unique UNIQUE (interface_id, address),
    CONSTRAINT ip_addresses_prefix_check      CHECK (prefix BETWEEN 0 AND 128)
);

CREATE INDEX IF NOT EXISTS idx_ip_addresses_iface  ON ip_addresses (interface_id);
CREATE INDEX IF NOT EXISTS idx_ip_addresses_vip    ON ip_addresses (is_vip) WHERE is_vip;
CREATE INDEX IF NOT EXISTS idx_ip_addresses_active ON ip_addresses (active) WHERE active;

-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS ip_addresses;
DROP TABLE IF EXISTS network_interfaces;
-- +goose StatementEnd
