-- PostgreSQL 17 schema (converted from MySQL wg.sql)

CREATE TABLE IF NOT EXISTS users (
    id              BIGSERIAL PRIMARY KEY,
    username        VARCHAR(64)  NOT NULL UNIQUE,
    email           VARCHAR(128) NOT NULL UNIQUE,
    password_hash   VARCHAR(255) NOT NULL,
    role            VARCHAR(16)  NOT NULL DEFAULT 'user' CHECK (role IN ('user', 'admin')),
    is_approved     BOOLEAN      NOT NULL DEFAULT FALSE,
    created_at      TIMESTAMPTZ  NOT NULL DEFAULT NOW(),
    updated_at      TIMESTAMPTZ
);

CREATE TABLE IF NOT EXISTS site_status (
    id          BIGSERIAL PRIMARY KEY,
    is_online   BOOLEAN     NOT NULL DEFAULT TRUE,
    message     TEXT        NOT NULL DEFAULT '',
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS servers (
    id              BIGSERIAL PRIMARY KEY,
    name            VARCHAR(100) NOT NULL,
    ip              VARCHAR(45)  NOT NULL,
    port            INTEGER      NOT NULL DEFAULT 54321,
    panel_username  VARCHAR(64)  NOT NULL,
    panel_password  VARCHAR(255) NOT NULL,
    status          VARCHAR(16)  NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'inactive')),
    created_at      TIMESTAMPTZ  NOT NULL DEFAULT NOW(),
    updated_at      TIMESTAMPTZ,
    inbound_id      INTEGER      NOT NULL DEFAULT 1
);

CREATE TABLE IF NOT EXISTS servers_simple (
    id          BIGSERIAL PRIMARY KEY,
    name        VARCHAR(100) NOT NULL,
    host        VARCHAR(255) NOT NULL,
    port        INTEGER      NOT NULL,
    country     VARCHAR(255) DEFAULT '?',
    status      VARCHAR(16)  DEFAULT 'active',
    created_at  TIMESTAMPTZ  NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS countries (
    id          BIGSERIAL PRIMARY KEY,
    code        VARCHAR(8)   NOT NULL UNIQUE,
    name_ru     VARCHAR(128) NOT NULL,
    name_en     VARCHAR(128) NOT NULL,
    flag        VARCHAR(16)  NOT NULL DEFAULT '',
    sort_order  INTEGER      DEFAULT 0
);

CREATE TABLE IF NOT EXISTS wg_configs (
    id                  BIGSERIAL PRIMARY KEY,
    token               VARCHAR(32) UNIQUE,
    user_id             BIGINT REFERENCES users(id) ON DELETE SET NULL,
    config_content      TEXT NOT NULL,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    original_filename   VARCHAR(255) NOT NULL DEFAULT 'wg_config.conf',
    is_demo             BOOLEAN DEFAULT FALSE
);

CREATE INDEX IF NOT EXISTS idx_wg_configs_user_id ON wg_configs(user_id);

CREATE TABLE IF NOT EXISTS wg_config_settings (
    setting_key     VARCHAR(50) PRIMARY KEY,
    setting_value   VARCHAR(10) NOT NULL,
    updated_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS demo_keys (
    id          BIGSERIAL PRIMARY KEY,
    config_id   BIGINT NOT NULL REFERENCES wg_configs(id) ON DELETE CASCADE,
    token       VARCHAR(32) NOT NULL UNIQUE,
    expires_at  TIMESTAMPTZ NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS awg_configs (
    id              BIGSERIAL PRIMARY KEY,
    config_name     VARCHAR(100) NOT NULL,
    config_content  TEXT NOT NULL,
    qr_code_url     VARCHAR(512) NOT NULL,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS amnezia_configs (
    id                  BIGSERIAL PRIMARY KEY,
    config_name         VARCHAR(255) NOT NULL,
    original_filename   VARCHAR(255) NOT NULL,
    file_path           VARCHAR(512) NOT NULL,
    file_url            VARCHAR(512) NOT NULL,
    config_content      TEXT NOT NULL,
    host                VARCHAR(255) NOT NULL,
    port                INTEGER NOT NULL DEFAULT 51820,
    username            VARCHAR(255),
    password            VARCHAR(255),
    description         TEXT,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS vless_configs (
    id                  BIGSERIAL PRIMARY KEY,
    vless_uri           TEXT NOT NULL,
    subscription_url    TEXT NOT NULL,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS admin_uploads (
    id              BIGSERIAL PRIMARY KEY,
    original_name   VARCHAR(255) NOT NULL,
    stored_name     VARCHAR(255) NOT NULL,
    file_path       VARCHAR(512) NOT NULL,
    file_url        VARCHAR(512) NOT NULL DEFAULT '',
    file_size       INTEGER NOT NULL,
    uploaded_at     TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS user_servers (
    id          BIGSERIAL PRIMARY KEY,
    user_id     BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    server_id   BIGINT NOT NULL REFERENCES servers(id) ON DELETE CASCADE,
    inbound_id  INTEGER NOT NULL,
    protocol    VARCHAR(20) NOT NULL,
    client_id   VARCHAR(64) NOT NULL,
    email       VARCHAR(128) NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_user_servers_user ON user_servers(user_id);
CREATE INDEX IF NOT EXISTS idx_user_servers_server ON user_servers(server_id);

CREATE TABLE IF NOT EXISTS license_keys (
    id          BIGSERIAL PRIMARY KEY,
    key_value   CHAR(36) NOT NULL UNIQUE,
    server_id   BIGINT NOT NULL REFERENCES servers(id) ON DELETE CASCADE,
    protocol    VARCHAR(20) NOT NULL DEFAULT 'vless',
    client_id   VARCHAR(64) NOT NULL,
    email       VARCHAR(128) NOT NULL DEFAULT 'license@ultravpn.cc',
    used_by     BIGINT REFERENCES users(id) ON DELETE SET NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    expires_at  TIMESTAMPTZ
);

CREATE TABLE IF NOT EXISTS rate_limits (
    id          BIGSERIAL PRIMARY KEY,
    user_id     BIGINT NOT NULL,
    action      VARCHAR(100) NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_rate_limits_user_action_time ON rate_limits(user_id, action, created_at);

CREATE TABLE IF NOT EXISTS app_meta (
    key         VARCHAR(64) PRIMARY KEY,
    value       TEXT NOT NULL DEFAULT '',
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

INSERT INTO site_status (id, is_online, message)
VALUES (1, TRUE, 'Сайт работает в штатном режиме.')
ON CONFLICT (id) DO NOTHING;

INSERT INTO wg_config_settings (setting_key, setting_value) VALUES
    ('show_zip_full', '0'),
    ('show_zip_conf', '1')
ON CONFLICT (setting_key) DO NOTHING;
