-- +goose Up
-- +goose StatementBegin

-- v1.0.49: backends wird vom Single-Server-Endpoint zum Pool.
-- Bisher: backends.address/port → genau ein Upstream.
-- Jetzt: backends = Pool-Definition (LB-Algo, Healthcheck), die
-- konkreten Upstreams leben in backend_servers (1:N).
-- Damit kann eine Domain → ein Backend → N Server (HAProxy macht
-- den Loadbalance laut backends.lb_algorithm).

CREATE TABLE IF NOT EXISTS backend_servers (
    id          BIGSERIAL PRIMARY KEY,
    backend_id  BIGINT NOT NULL REFERENCES backends(id) ON DELETE CASCADE,
    name        TEXT NOT NULL,
    address     TEXT NOT NULL,
    port        INTEGER NOT NULL,
    weight      INTEGER NOT NULL DEFAULT 100,
    backup      BOOLEAN NOT NULL DEFAULT FALSE,
    active      BOOLEAN NOT NULL DEFAULT TRUE,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT backend_servers_name_unique  UNIQUE (backend_id, name),
    CONSTRAINT backend_servers_port_check   CHECK (port > 0 AND port < 65536),
    CONSTRAINT backend_servers_weight_check CHECK (weight >= 0 AND weight <= 256)
);

CREATE INDEX IF NOT EXISTS idx_backend_servers_backend
    ON backend_servers (backend_id);
CREATE INDEX IF NOT EXISTS idx_backend_servers_active
    ON backend_servers (backend_id, active) WHERE active;

-- LB-Algorithmus pro Backend. Default roundrobin entspricht haproxy-
-- default; source = sticky-per-Source-IP (für stateful Apps ohne
-- shared session store).
ALTER TABLE backends
    ADD COLUMN IF NOT EXISTS lb_algorithm TEXT NOT NULL DEFAULT 'roundrobin';

ALTER TABLE backends
    DROP CONSTRAINT IF EXISTS backends_lb_check;
ALTER TABLE backends
    ADD CONSTRAINT backends_lb_check
        CHECK (lb_algorithm IN ('roundrobin', 'leastconn', 'source'));

-- Daten-Migration: jede bisherige backends-Row produziert genau eine
-- backend_servers-Row mit demselben address/port. name = backends.name
-- damit der HAProxy-server-id stabil bleibt (haproxy stats / logs
-- referenzieren ihn). Idempotent — bei Re-Apply gibt's einen Skip
-- über das Unique-Constraint.
INSERT INTO backend_servers (backend_id, name, address, port, active)
SELECT id, name, address, port, active
  FROM backends
 WHERE address IS NOT NULL AND port IS NOT NULL
ON CONFLICT (backend_id, name) DO NOTHING;

-- Erst nach erfolgreichem Insert die alten Spalten droppen. Wenn die
-- Migration mittendrin abbricht, sind die Daten in beiden Tabellen
-- vorhanden — wir verlieren nichts.
ALTER TABLE backends DROP COLUMN IF EXISTS address;
ALTER TABLE backends DROP COLUMN IF EXISTS port;

-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
ALTER TABLE backends ADD COLUMN IF NOT EXISTS address TEXT;
ALTER TABLE backends ADD COLUMN IF NOT EXISTS port    INTEGER;

UPDATE backends b
   SET address = bs.address,
       port    = bs.port
  FROM (
    SELECT DISTINCT ON (backend_id) backend_id, address, port
      FROM backend_servers
     ORDER BY backend_id, id ASC
  ) bs
 WHERE b.id = bs.backend_id;

ALTER TABLE backends DROP CONSTRAINT IF EXISTS backends_lb_check;
ALTER TABLE backends DROP COLUMN IF EXISTS lb_algorithm;
DROP TABLE IF EXISTS backend_servers;
-- +goose StatementEnd
