create table if not exists "user"
(
    uid             uuid                     not null
        primary key,
    username        varchar(255)             not null,
    display_name    varchar(255),
    avatar_url      varchar(255),
    website_url     varchar(255),
    organization    varchar(255),
    last_sign_in_at timestamp with time zone,
    created_at      timestamp with time zone not null,
    updated_at      timestamp with time zone not null
);

create index if not exists idx_user_username
    on "user" (username);

create table if not exists user_password
(
    "user"        uuid                     not null
        primary key,
    password_hash varchar(255)             not null,
    password_salt varchar(255),
    is_active     boolean default true     not null,
    created_at    timestamp with time zone not null,
    updated_at    timestamp with time zone not null
);

create table if not exists user_email
(
    "user"     uuid                     not null
        primary key,
    email      varchar(255)             not null,
    created_at timestamp with time zone not null
);

create index if not exists idx_user_email_email
    on user_email (email);

create table if not exists user_2fa
(
    "user"       uuid                     not null
        primary key,
    method       varchar(255)             not null,
    secret       varchar(255),
    backup_codes jsonb                    not null,
    is_enabled   boolean default false    not null,
    created_at   timestamp with time zone not null,
    updated_at   timestamp with time zone not null
);

create table if not exists user_notification
(
    "user"                        uuid                     not null
        primary key,
    email_enabled                 boolean default false    not null,
    in_app_enabled                boolean default true     not null,
    push_enabled                  boolean default false    not null,
    digest_mode                   varchar(255)             not null,
    dnd_enabled                   boolean default false    not null,
    dnd_start_minute              integer,
    dnd_end_minute                integer,
    marketing_enabled             boolean default true     not null,
    security_enabled              boolean default true     not null,
    product_enabled               boolean default true     not null,
    created_at                    timestamp with time zone not null,
    updated_at                    timestamp with time zone not null,
    push_subscription_endpoint    text,
    push_subscription_keys_p256dh text,
    push_subscription_keys_auth   text
);

create table if not exists user_preferences
(
    "user"               uuid                     not null
        primary key,
    language             varchar(255)             not null,
    theme                varchar(255)             not null,
    timezone             varchar(255)             not null,
    email_notifications  boolean default true     not null,
    in_app_notifications boolean default true     not null,
    created_at           timestamp with time zone not null,
    updated_at           timestamp with time zone not null
);

create table if not exists user_password_reset
(
    token      varchar(255)             not null
        primary key,
    user_uid   uuid                     not null,
    expires_at timestamp with time zone not null,
    used       boolean default false    not null,
    created_at timestamp with time zone not null
);

create index if not exists idx_user_password_reset_user_uid
    on user_password_reset (user_uid);

create table if not exists user_relation
(
    id            bigserial
        primary key,
    "user"        uuid                     not null,
    target        uuid                     not null,
    relation_type varchar(255)             not null,
    created_at    timestamp with time zone not null
);

create index if not exists idx_user_relation_user
    on user_relation ("user");

create index if not exists idx_user_relation_target
    on user_relation (target);

create table if not exists user_ssh_key
(
    id           bigserial
        primary key,
    "user"       uuid                     not null,
    title        varchar(255)             not null,
    public_key   text                     not null,
    fingerprint  varchar(255)             not null,
    key_type     varchar(255)             not null,
    key_bits     integer,
    is_verified  boolean default false    not null,
    last_used_at timestamp with time zone,
    expires_at   timestamp with time zone,
    is_revoked   boolean default false    not null,
    created_at   timestamp with time zone not null,
    updated_at   timestamp with time zone not null
);

create index if not exists idx_user_ssh_key_user
    on user_ssh_key ("user");

create table if not exists user_token
(
    id         bigserial
        primary key,
    "user"     uuid                     not null,
    name       varchar(255)             not null,
    token_hash varchar(255)             not null,
    scopes     jsonb                    not null,
    expires_at timestamp with time zone,
    is_revoked boolean default false    not null,
    created_at timestamp with time zone not null,
    updated_at timestamp with time zone not null
);

create index if not exists idx_user_token_user
    on user_token ("user");

create table if not exists user_activity_log
(
    id         bigserial
        primary key,
    user_uid   uuid,
    action     varchar(255)             not null,
    ip_address varchar(255),
    user_agent varchar(255),
    details    jsonb                    not null,
    created_at timestamp with time zone not null
);

create index if not exists idx_user_activity_log_user_uid
    on user_activity_log (user_uid);

create index if not exists idx_user_activity_log_created_at
    on user_activity_log (created_at);

create table if not exists project_access_log
(
    id         bigserial
        primary key,
    project    uuid                     not null,
    actor_uid  uuid,
    action     varchar(255)             not null,
    ip_address varchar(255),
    user_agent varchar(255),
    created_at timestamp with time zone not null
);

create index if not exists idx_project_access_log_project
    on project_access_log (project);

create index if not exists idx_project_access_log_created_at
    on project_access_log (created_at);

create table if not exists project_audit_log
(
    id         bigserial
        primary key,
    project    uuid                     not null,
    actor      uuid                     not null,
    action     text                     not null,
    details    jsonb,
    ip_address varchar(255),
    user_agent varchar(255),
    created_at timestamp with time zone not null
);

create index if not exists idx_project_audit_log_project
    on project_audit_log (project);

create index if not exists idx_project_audit_log_created_at
    on project_audit_log (created_at);

create table if not exists project_billing
(
    project_uuid uuid                     not null
        primary key,
    balance      numeric default 0.0      not null,
    currency     text                     not null,
    user_uuid    uuid,
    updated_at   timestamp with time zone not null,
    created_at   timestamp with time zone not null
);

create table if not exists project_billing_history
(
    uid        uuid                     not null
        primary key,
    project    uuid                     not null,
    "user"     uuid,
    amount     numeric                  not null,
    currency   text                     not null,
    reason     text                     not null,
    extra      jsonb,
    created_at timestamp with time zone not null
);

create index if not exists idx_project_billing_history_project
    on project_billing_history (project);

create table if not exists project_follow
(
    id         bigserial
        primary key,
    project    uuid                     not null,
    "user"     uuid                     not null,
    created_at timestamp with time zone not null,
    unique (project, "user")
);

create unique index if not exists idx_project_follow_project_user
    on project_follow (project, "user");

create table if not exists project_history_name
(
    id           bigserial
        primary key,
    project_uid  uuid                     not null,
    history_name varchar(255)             not null,
    changed_at   timestamp with time zone not null
);

create index if not exists idx_project_history_name_project_uid
    on project_history_name (project_uid);

create table if not exists project_label
(
    id           bigserial
        primary key,
    project_uuid uuid                     not null,
    label_id     bigint                   not null,
    relation_at  timestamp with time zone not null
);

create index if not exists idx_project_label_project
    on project_label (project_uuid);

create table if not exists project_like
(
    project    uuid                     not null,
    "user"     uuid                     not null,
    created_at timestamp with time zone not null,
    primary key (project, "user")
);

create table if not exists project_member_invitations
(
    id          bigserial
        primary key,
    project     uuid                     not null,
    "user"      uuid                     not null,
    invited_by  uuid                     not null,
    scope       varchar(255)             not null,
    accepted    boolean default false    not null,
    accepted_at timestamp with time zone,
    rejected    boolean default false    not null,
    rejected_at timestamp with time zone,
    created_at  timestamp with time zone not null
);

create index if not exists idx_project_member_invitations_project_user
    on project_member_invitations (project, "user");

create table if not exists project_member_join_answers
(
    id         bigserial
        primary key,
    project    uuid                     not null,
    "user"     uuid                     not null,
    request_id bigint                   not null,
    question   varchar(255)             not null,
    answer     varchar(255)             not null,
    created_at timestamp with time zone not null
);

create index if not exists idx_project_member_join_answers_request_id
    on project_member_join_answers (request_id);

create table if not exists project_member_join_request
(
    id            bigserial
        primary key,
    project       uuid                     not null,
    "user"        uuid                     not null,
    status        varchar(255)             not null,
    message       text,
    processed_by  uuid,
    processed_at  timestamp with time zone,
    reject_reason text,
    created_at    timestamp with time zone not null,
    updated_at    timestamp with time zone not null
);

create index if not exists idx_project_member_join_request_project_user
    on project_member_join_request (project, "user");

create index if not exists idx_project_member_join_request_status
    on project_member_join_request (status);

create table if not exists project_member_join_settings
(
    id                bigserial
        primary key,
    project           uuid                     not null,
    require_approval  boolean default false    not null,
    require_questions boolean default false    not null,
    questions         jsonb                    not null,
    created_at        timestamp with time zone not null,
    updated_at        timestamp with time zone not null
);

create table if not exists project_members
(
    id           bigserial
        primary key,
    project_uuid uuid                     not null,
    user_uuid    uuid                     not null,
    scope        varchar(255)             not null,
    joined_at    timestamp with time zone not null,
    unique (project_uuid, user_uuid)
);

create unique index if not exists idx_project_members_project_user
    on project_members (project_uuid, user_uuid);

create table if not exists project_watch
(
    id                    bigserial
        primary key,
    project               uuid                     not null,
    "user"                uuid                     not null,
    notifications_enabled boolean default true     not null,
    created_at            timestamp with time zone not null,
    updated_at            timestamp with time zone not null,
    unique (project, "user")
);

create unique index if not exists idx_project_watch_project_user
    on project_watch (project, "user");

create table if not exists repo
(
    id                     uuid                     not null
        primary key,
    repo_name              varchar(255)             not null,
    project                uuid                     not null,
    description            text,
    default_branch         varchar(255)             not null,
    is_private             boolean default false    not null,
    storage_path           varchar(255)             not null,
    created_by             uuid                     not null,
    created_at             timestamp with time zone not null,
    updated_at             timestamp with time zone not null,
    ai_code_review_enabled boolean default false    not null
);

create index if not exists idx_repo_project
    on repo (project);

create index if not exists idx_repo_repo_name
    on repo (repo_name);

create table if not exists repo_branch
(
    repo       uuid                     not null,
    name       varchar(255)             not null,
    oid        varchar(255)             not null,
    upstream   varchar(255),
    head       boolean default false    not null,
    created_at timestamp with time zone not null,
    updated_at timestamp with time zone not null,
    primary key (repo, name)
);

create index if not exists idx_repo_branch_repo
    on repo_branch (repo);

create table if not exists repo_branch_protect
(
    id                     bigserial
        primary key,
    repo_uuid              uuid                  not null,
    branch                 varchar(255)          not null,
    forbid_push            boolean default false not null,
    forbid_pull            boolean default false not null,
    forbid_merge           boolean default false not null,
    forbid_deletion        boolean default false not null,
    forbid_force_push      boolean default false not null,
    forbid_tag_push        boolean default false not null,
    required_approvals     integer default 0     not null,
    dismiss_stale_reviews  boolean default false not null,
    require_linear_history boolean default false not null,
    allow_fork_syncing     boolean default true  not null,
    unique (repo_uuid, branch)
);

create unique index if not exists idx_repo_branch_protect_repo_branch
    on repo_branch_protect (repo_uuid, branch);

create table if not exists repo_collaborator
(
    repo       uuid                     not null,
    "user"     uuid                     not null,
    scope      varchar(255)             not null,
    created_at timestamp with time zone not null,
    primary key (repo, "user")
);

create table if not exists repo_commit
(
    id             bigserial
        primary key,
    repo           uuid                     not null,
    oid            varchar(255)             not null,
    author_name    varchar(255)             not null,
    author_email   varchar(255)             not null,
    author         uuid,
    commiter_name  varchar(255)             not null,
    commiter_email varchar(255)             not null,
    commiter       uuid,
    message        text                     not null,
    parent         jsonb                    not null,
    created_at     timestamp with time zone not null
);

create index if not exists idx_repo_commit_repo
    on repo_commit (repo);

create index if not exists idx_repo_commit_oid
    on repo_commit (oid);

create table if not exists repo_fork
(
    id          bigserial
        primary key,
    parent_repo uuid                     not null,
    forked_repo uuid                     not null,
    forked_by   uuid                     not null,
    forked_at   timestamp with time zone not null
);

create index if not exists idx_repo_fork_parent_repo
    on repo_fork (parent_repo);

create unique index if not exists idx_repo_fork_forked_repo
    on repo_fork (forked_repo);

create table if not exists repo_history_name
(
    id          bigserial
        primary key,
    repo_uuid   uuid                     not null,
    project_uid uuid                     not null,
    name        varchar(255)             not null,
    change_at   timestamp with time zone not null
);

create index if not exists idx_repo_history_name_repo
    on repo_history_name (repo_uuid);

create table if not exists repo_hook
(
    id         bigserial
        primary key,
    repo_uuid  uuid                     not null,
    event      jsonb                    not null,
    script     text                     not null,
    created_at timestamp with time zone not null
);

create index if not exists idx_repo_hook_repo
    on repo_hook (repo_uuid);

create table if not exists repo_lfs_lock
(
    repo_uuid   uuid                     not null,
    path        varchar(255)             not null,
    lock_type   varchar(255)             not null,
    locked_by   uuid                     not null,
    locked_at   timestamp with time zone not null,
    unlocked_at timestamp with time zone,
    primary key (repo_uuid, path)
);

create table if not exists repo_lfs_object
(
    id           bigserial
        primary key,
    oid          varchar(255)             not null,
    repo_uuid    uuid                     not null,
    size         bigint                   not null,
    storage_path varchar(255)             not null,
    uploaded_by  uuid,
    uploaded_at  timestamp with time zone not null
);

create index if not exists idx_repo_lfs_object_repo_oid
    on repo_lfs_object (repo_uuid, oid);

create table if not exists repo_lock
(
    repo_uuid   uuid                     not null,
    path        varchar(255)             not null,
    lock_type   varchar(255)             not null,
    locked_by   uuid                     not null,
    acquired_at timestamp with time zone not null,
    released_at timestamp with time zone,
    primary key (repo_uuid, path)
);

create table if not exists repo_star
(
    id         bigserial
        primary key,
    repo_uuid  uuid                     not null,
    user_uuid  uuid                     not null,
    created_at timestamp with time zone not null,
    unique (repo_uuid, user_uuid)
);

create unique index if not exists idx_repo_star_repo_user
    on repo_star (repo_uuid, user_uuid);

create table if not exists repo_tag
(
    repo_uuid    uuid                     not null,
    name         varchar(255)             not null,
    oid          varchar(255)             not null,
    color        varchar(255),
    description  text,
    created_at   timestamp with time zone not null,
    tagger_name  varchar(255)             not null,
    tagger_email varchar(255)             not null,
    tagger_uuid  uuid,
    primary key (repo_uuid, name)
);

create table if not exists repo_upstream
(
    id            bigserial
        primary key,
    repo_uuid     uuid                     not null
        unique,
    source_url    varchar(255)             not null,
    direction     varchar(255)             not null,
    schedule_cron varchar(255),
    last_run_at   timestamp with time zone,
    next_run_at   timestamp with time zone,
    status        varchar(255)             not null,
    created_at    timestamp with time zone not null,
    updated_at    timestamp with time zone not null
);

create unique index if not exists idx_repo_upstream_repo
    on repo_upstream (repo_uuid);

create table if not exists repo_watch
(
    id             bigserial
        primary key,
    user_uuid      uuid                     not null,
    repo_uuid      uuid                     not null,
    show_dashboard boolean default false    not null,
    notify_email   boolean default false    not null,
    created_at     timestamp with time zone not null,
    updated_at     timestamp with time zone not null,
    unique (user_uuid, repo_uuid)
);

create unique index if not exists idx_repo_watch_user_repo
    on repo_watch (user_uuid, repo_uuid);

create table if not exists repo_webhook
(
    id                bigserial
        primary key,
    repo_uuid         uuid                     not null,
    event             jsonb                    not null,
    url               varchar(255),
    access_key        varchar(255),
    secret_key        varchar(255),
    created_at        timestamp with time zone not null,
    last_delivered_at timestamp with time zone,
    touch_count       bigint default 0         not null
);

create index if not exists idx_repo_webhook_repo
    on repo_webhook (repo_uuid);

create table if not exists issue
(
    id            uuid                     not null
        primary key,
    project       uuid                     not null,
    number        bigint                   not null,
    title         varchar(255)             not null,
    body          text,
    state         varchar(255)             not null,
    author        uuid                     not null,
    milestone     varchar(255),
    created_at    timestamp with time zone not null,
    updated_at    timestamp with time zone not null,
    closed_at     timestamp with time zone,
    created_by_ai boolean default false    not null
);

create index if not exists idx_issue_project
    on issue (project);

create index if not exists idx_issue_author
    on issue (author);

create index if not exists idx_issue_state
    on issue (state);

create table if not exists issue_assignee
(
    issue       uuid                     not null,
    "user"      uuid                     not null,
    assigned_at timestamp with time zone not null,
    primary key (issue, "user")
);

create table if not exists issue_comment
(
    id         bigserial
        primary key,
    issue      uuid                     not null,
    author     uuid                     not null,
    body       text                     not null,
    created_at timestamp with time zone not null,
    updated_at timestamp with time zone not null
);

create index if not exists idx_issue_comment_issue
    on issue_comment (issue);

create table if not exists issue_comment_reaction
(
    comment_id bigint                   not null,
    user_uuid  uuid                     not null,
    reaction   varchar(255)             not null,
    created_at timestamp with time zone not null,
    primary key (comment_id, user_uuid, reaction)
);

create table if not exists issue_label
(
    issue       uuid                     not null,
    label       bigint                   not null,
    relation_at timestamp with time zone not null,
    primary key (issue, label)
);

create table if not exists issue_pull_request
(
    issue       uuid                     not null,
    repo        uuid                     not null,
    number      bigint                   not null,
    relation_at timestamp with time zone not null,
    primary key (issue, repo, number)
);

create table if not exists issue_reaction
(
    issue_uuid uuid                     not null,
    user_uuid  uuid                     not null,
    reaction   varchar(255)             not null,
    created_at timestamp with time zone not null,
    primary key (issue_uuid, user_uuid, reaction)
);

create table if not exists issue_repo
(
    issue       uuid                     not null,
    repo        uuid                     not null,
    relation_at timestamp with time zone not null,
    primary key (issue, repo)
);

create table if not exists issue_subscriber
(
    issue      uuid                     not null,
    "user"     uuid                     not null,
    subscribed boolean default true     not null,
    created_at timestamp with time zone not null,
    primary key (issue, "user")
);

create table if not exists pull_request
(
    repo          uuid                     not null,
    number        bigint                   not null,
    issue         uuid                     not null,
    title         varchar(255)             not null,
    body          text,
    author        uuid                     not null,
    base          varchar(255)             not null,
    head          varchar(255)             not null,
    status        varchar(255)             not null,
    merged_by     uuid,
    created_at    timestamp with time zone not null,
    updated_at    timestamp with time zone not null,
    merged_at     timestamp with time zone,
    created_by_ai boolean default false    not null,
    primary key (repo, number)
);

create index if not exists idx_pull_request_repo
    on pull_request (repo);

create index if not exists idx_pull_request_author
    on pull_request (author);

create index if not exists idx_pull_request_status
    on pull_request (status);

create table if not exists pull_request_commit
(
    repo            uuid                     not null,
    number          bigint                   not null,
    commit          varchar(255)             not null,
    message         text                     not null,
    author_name     varchar(255)             not null,
    author_email    varchar(255)             not null,
    authored_at     timestamp with time zone not null,
    committer_name  varchar(255)             not null,
    committer_email varchar(255)             not null,
    committed_at    timestamp with time zone not null,
    created_at      timestamp with time zone not null,
    primary key (repo, number, commit)
);

create table if not exists pull_request_review
(
    repo         uuid                     not null,
    number       bigint                   not null,
    reviewer     uuid                     not null,
    state        varchar(255)             not null,
    body         text,
    submitted_at timestamp with time zone,
    created_at   timestamp with time zone not null,
    updated_at   timestamp with time zone not null,
    primary key (repo, number, reviewer)
);

create table if not exists pull_request_review_comment
(
    repo        uuid                     not null,
    number      bigint                   not null,
    id          bigint                   not null,
    review      uuid,
    path        text,
    side        varchar(255),
    line        bigint,
    old_line    bigint,
    body        text                     not null,
    author      uuid                     not null,
    created_at  timestamp with time zone not null,
    updated_at  timestamp with time zone not null,
    resolved    boolean default false    not null,
    in_reply_to bigint,
    primary key (repo, number, id)
);

create table if not exists room_category
(
    id           uuid                     not null
        primary key,
    project_uuid uuid                     not null,
    name         varchar(255)             not null,
    position     integer                  not null,
    created_by   uuid                     not null,
    created_at   timestamp with time zone not null
);

create index if not exists idx_room_category_project
    on room_category (project_uuid);

create table if not exists room
(
    id          uuid                     not null
        primary key,
    project     uuid                     not null,
    room_name   varchar(255)             not null,
    public      boolean default false    not null,
    category    uuid,
    created_by  uuid                     not null,
    created_at  timestamp with time zone not null,
    last_msg_at timestamp with time zone not null
);

create index if not exists idx_room_project
    on room (project);

create index if not exists idx_room_category
    on room (category);

create table if not exists room_ai
(
    room          uuid                     not null,
    model         uuid                     not null,
    version       uuid,
    call_count    bigint  default 0        not null,
    last_call_at  timestamp with time zone,
    history_limit bigint,
    system_prompt text,
    temperature   double precision,
    max_tokens    bigint,
    use_exact     boolean default false    not null,
    think         boolean default false    not null,
    min_score     real,
    created_at    timestamp with time zone not null,
    updated_at    timestamp with time zone not null,
    stream        boolean default true     not null,
    agent_type    varchar(50),
    primary key (room, model)
);

create index if not exists idx_room_ai_agent_type
    on room_ai (agent_type)
    where (agent_type IS NOT NULL);

create table if not exists room_message
(
    id               uuid                     not null
        primary key,
    seq              bigint                   not null,
    room             uuid                     not null,
    sender_type      varchar(255)             not null,
    sender_id        uuid,
    thread           uuid,
    content          text                     not null,
    content_type     varchar(255)             not null,
    edited_at        timestamp with time zone,
    send_at          timestamp with time zone not null,
    revoked          timestamp with time zone,
    revoked_by       uuid,
    in_reply_to      uuid,
    content_tsv      tsvector,
    model_id         uuid,
    thinking_content text
);

create index if not exists idx_room_message_room_seq
    on room_message (room, seq);

create index if not exists idx_room_message_thread
    on room_message (thread);

create index if not exists idx_room_message_send_at
    on room_message (send_at);

create index if not exists idx_room_message_content_tsv
    on room_message using gin (content_tsv);

create index if not exists idx_room_message_model_id
    on room_message (model_id)
    where (model_id IS NOT NULL);



create table if not exists room_pin
(
    room      uuid                     not null,
    message   uuid                     not null,
    pinned_by uuid                     not null,
    pinned_at timestamp with time zone not null,
    primary key (room, message)
);

create table if not exists room_thread
(
    id                   uuid                     not null
        primary key,
    room                 uuid                     not null,
    parent               bigint                   not null,
    created_by           uuid                     not null,
    participants         jsonb                    not null,
    last_message_at      timestamp with time zone not null,
    last_message_preview text,
    created_at           timestamp with time zone not null,
    updated_at           timestamp with time zone not null
);

create index if not exists idx_room_thread_room
    on room_thread (room);

create table if not exists ai_model_provider
(
    id           uuid                     not null
        primary key,
    name         varchar(255)             not null,
    display_name varchar(255)             not null,
    website      varchar(255),
    status       varchar(255)             not null,
    created_at   timestamp with time zone not null,
    updated_at   timestamp with time zone not null
);

create table if not exists ai_model
(
    id                uuid                     not null
        primary key,
    provider_id       uuid                     not null,
    name              varchar(255)             not null,
    modality          varchar(255)             not null,
    capability        varchar(255)             not null,
    context_length    bigint                   not null,
    max_output_tokens bigint,
    training_cutoff   timestamp with time zone,
    is_open_source    boolean default false    not null,
    status            varchar(255)             not null,
    created_at        timestamp with time zone not null,
    updated_at        timestamp with time zone not null
);

create index if not exists idx_ai_model_provider_id
    on ai_model (provider_id);

create table if not exists ai_model_version
(
    id           uuid                     not null
        primary key,
    model_id     uuid                     not null,
    version      varchar(255)             not null,
    release_date timestamp with time zone,
    change_log   text,
    is_default   boolean default false    not null,
    status       varchar(255)             not null,
    created_at   timestamp with time zone not null
);

create index if not exists idx_ai_model_version_model_id
    on ai_model_version (model_id);

create table if not exists ai_model_capability
(
    id               bigserial
        primary key,
    model_version_id uuid                     not null,
    capability       varchar(255)             not null,
    is_supported     boolean default false    not null,
    created_at       timestamp with time zone not null
);

create index if not exists idx_ai_model_capability_model_version_id
    on ai_model_capability (model_version_id);

create table if not exists ai_model_parameter_profile
(
    id                          bigserial
        primary key,
    model_version_id            uuid                  not null
        unique,
    temperature_min             double precision      not null,
    temperature_max             double precision      not null,
    top_p_min                   double precision      not null,
    top_p_max                   double precision      not null,
    frequency_penalty_supported boolean default false not null,
    presence_penalty_supported  boolean default false not null
);

create unique index if not exists idx_ai_model_parameter_profile_model_version_id
    on ai_model_parameter_profile (model_version_id);

create table if not exists ai_model_pricing
(
    id                         bigserial
        primary key,
    model_version_id           uuid                     not null,
    input_price_per_1k_tokens  varchar(255)             not null,
    output_price_per_1k_tokens varchar(255)             not null,
    currency                   varchar(255)             not null,
    effective_from             timestamp with time zone not null
);

create index if not exists idx_ai_model_pricing_model_version_id
    on ai_model_pricing (model_version_id);

create table if not exists ai_session
(
    id            uuid                     not null
        primary key,
    room          uuid                     not null,
    model         uuid                     not null,
    version       uuid                     not null,
    token_input   bigint default 0         not null,
    token_output  bigint default 0         not null,
    latency_ms    bigint,
    cost          double precision,
    currency      varchar(255),
    error_message text,
    error_code    varchar(255),
    created_at    timestamp with time zone not null
);

create index if not exists idx_ai_session_room
    on ai_session (room);

create table if not exists ai_tool_call
(
    tool_call_id      varchar(255)             not null,
    session           uuid                     not null,
    tool_name         varchar(255)             not null,
    caller            uuid                     not null,
    arguments         jsonb                    not null,
    result            jsonb                    not null,
    status            varchar(255)             not null,
    execution_time_ms bigint,
    error_message     text,
    error_stack       text,
    retry_count       integer default 0        not null,
    created_at        timestamp with time zone not null,
    completed_at      timestamp with time zone,
    updated_at        timestamp with time zone not null,
    primary key (tool_call_id, session)
);

create index if not exists idx_ai_tool_call_session
    on ai_tool_call (session);

create index if not exists idx_ai_tool_call_status
    on ai_tool_call (status);

create table if not exists ai_tool_auth
(
    session          uuid                     not null,
    tool_call_id     varchar(255)             not null,
    method           varchar(255)             not null,
    arguments        text                     not null,
    decision         boolean default false    not null,
    reason           varchar(255)             not null,
    decision_by      uuid                     not null,
    decision_comment text,
    logs             jsonb                    not null,
    expires_at       timestamp with time zone,
    authorized_at    timestamp with time zone,
    created_at       timestamp with time zone not null,
    updated_at       timestamp with time zone not null,
    primary key (session, tool_call_id)
);

create table if not exists label
(
    id           bigserial
        primary key,
    project_uuid uuid         not null,
    name         varchar(255) not null,
    color        varchar(255) not null
);

create index if not exists idx_label_project
    on label (project_uuid);

create table if not exists notify
(
    id          bigserial
        primary key,
    user_uuid   uuid                     not null,
    title       varchar(255)             not null,
    description text,
    content     text                     not null,
    url         varchar(255),
    kind        integer                  not null,
    read_at     timestamp with time zone,
    deleted_at  timestamp with time zone,
    created_at  timestamp with time zone not null
);

create index if not exists idx_notify_user
    on notify (user_uuid);

create index if not exists idx_notify_created_at
    on notify (created_at);

create table if not exists room_notifications
(
    id                 uuid                     not null
        primary key,
    room               uuid,
    project            uuid,
    user_id            uuid,
    notification_type  varchar(255)             not null,
    related_message_id uuid,
    related_user_id    uuid,
    related_room_id    uuid,
    title              varchar(255)             not null,
    content            text,
    metadata           jsonb,
    is_read            boolean default false    not null,
    is_archived        boolean default false    not null,
    created_at         timestamp with time zone not null,
    read_at            timestamp with time zone,
    expires_at         timestamp with time zone
);

create index if not exists idx_room_notifications_user_id_is_read
    on room_notifications (user_id, is_read);

create index if not exists idx_room_notifications_user_id_created_at
    on room_notifications (user_id, created_at);

create index if not exists idx_room_notifications_expires_at
    on room_notifications (expires_at);

create table if not exists user_email_change
(
    token      varchar(255)             not null
        primary key,
    user_uid   uuid                     not null,
    new_email  varchar(255)             not null,
    expires_at timestamp with time zone not null,
    used       boolean default false    not null,
    created_at timestamp with time zone not null
);

create index if not exists idx_user_email_change_user_uid
    on user_email_change (user_uid);

create table if not exists project_activity
(
    id           bigserial
        primary key,
    project      uuid                     not null,
    repo         uuid,
    actor        uuid                     not null,
    event_type   varchar(50)              not null,
    event_id     uuid,
    event_sub_id bigint,
    title        varchar(500)             not null,
    content      text,
    metadata     jsonb,
    is_private   boolean default false    not null,
    created_at   timestamp with time zone not null
);

create index if not exists idx_project_activity_project
    on project_activity (project);

create index if not exists idx_project_activity_created_at
    on project_activity (created_at desc);

create index if not exists idx_project_activity_event_type
    on project_activity (event_type);

create table if not exists room_message_reaction
(
    id         uuid                                   not null
        primary key,
    room       uuid                                   not null
        references room
            on delete cascade,
    message    uuid                                   not null
        references room_message
            on delete cascade,
    "user"     uuid                                   not null
        references "user"
            on delete cascade,
    emoji      varchar(50)                            not null,
    created_at timestamp with time zone default now() not null,
    unique (message, "user", emoji)
);

create index if not exists idx_room_message_reaction_message
    on room_message_reaction (message);

create index if not exists idx_room_message_reaction_user
    on room_message_reaction ("user");

create index if not exists idx_room_message_reaction_room
    on room_message_reaction (room);

create table if not exists room_message_edit_history
(
    id          uuid                                   not null
        primary key,
    message     uuid                                   not null
        references room_message
            on delete cascade,
    "user"      uuid                                   not null
        references "user"
            on delete cascade,
    old_content text                                   not null,
    new_content text                                   not null,
    edited_at   timestamp with time zone default now() not null
);

create index if not exists idx_room_message_edit_history_message
    on room_message_edit_history (message);

create index if not exists idx_room_message_edit_history_user
    on room_message_edit_history ("user");

create table if not exists project_board
(
    id           uuid                     default gen_random_uuid() not null
        primary key,
    project_uuid uuid                                               not null,
    name         varchar(255)                                       not null,
    description  text,
    created_by   uuid                                               not null,
    created_at   timestamp with time zone default now()             not null,
    updated_at   timestamp with time zone default now()             not null
);

create index if not exists idx_project_board_project
    on project_board (project_uuid);

create table if not exists project_board_column
(
    id         uuid    default gen_random_uuid() not null
        primary key,
    board_uuid uuid                              not null
        references project_board
            on delete cascade,
    name       varchar(255)                      not null,
    position   integer default 0                 not null,
    wip_limit  integer,
    color      varchar(20)
);

create index if not exists idx_project_board_column_board
    on project_board_column (board_uuid);

create table if not exists project_board_card
(
    id          uuid                     default gen_random_uuid() not null
        primary key,
    column_uuid uuid                                               not null
        references project_board_column
            on delete cascade,
    issue_id    bigint,
    project     uuid,
    title       varchar(500)                                       not null,
    description text,
    position    integer                  default 0                 not null,
    assignee_id uuid,
    due_date    timestamp with time zone,
    priority    varchar(10),
    created_by  uuid                                               not null,
    created_at  timestamp with time zone default now()             not null,
    updated_at  timestamp with time zone default now()             not null
);

create index if not exists idx_project_board_card_column
    on project_board_card (column_uuid);

create index if not exists idx_project_board_card_issue
    on project_board_card (issue_id)
    where (issue_id IS NOT NULL);

create table if not exists pull_request_review_request
(
    repo         uuid                                   not null,
    number       bigint                                 not null,
    reviewer     uuid                                   not null,
    requested_by uuid                                   not null,
    requested_at timestamp with time zone default now() not null,
    dismissed_at timestamp with time zone,
    dismissed_by uuid,
    primary key (repo, number, reviewer)
);

create table if not exists workspace
(
    id                     uuid                                          not null
        primary key,
    slug                   varchar(255)                                  not null,
    name                   varchar(255)                                  not null,
    description            text,
    avatar_url             varchar(255),
    plan                   varchar(50) default 'free'::character varying not null,
    billing_email          varchar(255),
    stripe_customer_id     varchar(255),
    stripe_subscription_id varchar(255),
    plan_expires_at        timestamp with time zone,
    deleted_at             timestamp with time zone,
    created_at             timestamp with time zone                      not null,
    updated_at             timestamp with time zone                      not null
);

create table if not exists project
(
    id           uuid                     not null
        primary key,
    name         varchar(255)             not null,
    display_name varchar(255)             not null,
    avatar_url   varchar(255),
    description  text,
    is_public    boolean default false    not null,
    created_by   uuid                     not null,
    created_at   timestamp with time zone not null,
    updated_at   timestamp with time zone not null,
    workspace_id uuid
                                          references workspace
                                              on delete set null
);

create index if not exists idx_project_name
    on project (name);

create index if not exists idx_project_created_by
    on project (created_by);

create index if not exists idx_project_workspace_id
    on project (workspace_id)
    where (workspace_id IS NOT NULL);

create unique index if not exists idx_workspace_slug
    on workspace (slug);

create index if not exists idx_workspace_deleted_at
    on workspace (deleted_at);

create table if not exists workspace_membership
(
    id                bigserial
        primary key,
    workspace_id      uuid                                            not null,
    user_id           uuid                                            not null,
    role              varchar(50) default 'member'::character varying not null,
    status            varchar(50) default 'active'::character varying not null,
    invited_by        uuid,
    joined_at         timestamp with time zone                        not null,
    invite_token      varchar(255),
    invite_expires_at timestamp with time zone,
    unique (workspace_id, user_id)
);

create unique index if not exists idx_workspace_membership_ws_user
    on workspace_membership (workspace_id, user_id);

create index if not exists idx_workspace_membership_user
    on workspace_membership (user_id);

create index if not exists idx_workspace_membership_invite_token
    on workspace_membership (invite_token)
    where (invite_token IS NOT NULL);

create table if not exists workspace_billing
(
    workspace_id  uuid                                            not null
        primary key
        references workspace
            on delete cascade,
    balance       numeric(20, 4) default 0                        not null,
    currency      varchar(10)    default 'USD'::character varying not null,
    monthly_quota numeric(20, 4) default 0                        not null,
    total_spent   numeric(20, 4) default 0                        not null,
    updated_at    timestamp with time zone                        not null,
    created_at    timestamp with time zone                        not null
);

create table if not exists workspace_billing_history
(
    uid          uuid                                         not null
        primary key,
    workspace_id uuid                                         not null
        references workspace
            on delete cascade,
    user_id      uuid,
    amount       numeric(20, 4)                               not null,
    currency     varchar(10) default 'USD'::character varying not null,
    reason       varchar(100)                                 not null,
    extra        jsonb,
    created_at   timestamp with time zone                     not null
);

create index if not exists idx_wsbh_workspace_id
    on workspace_billing_history (workspace_id);

create index if not exists idx_wsbh_created_at
    on workspace_billing_history (created_at desc);

create table if not exists project_skill
(
    id           bigserial
        primary key,
    project_uuid uuid                                                         not null,
    slug         varchar(255)                                                 not null,
    name         varchar(255)                                                 not null,
    description  text,
    source       varchar(20)              default 'manual'::character varying not null,
    repo_id      uuid,
    content      text                     default ''::text                    not null,
    metadata     jsonb                    default '{}'::jsonb                 not null,
    enabled      boolean                  default true                        not null,
    created_by   uuid,
    created_at   timestamp with time zone default now()                       not null,
    updated_at   timestamp with time zone default now()                       not null,
    commit_sha   varchar(40),
    blob_hash    varchar(40),
    unique (project_uuid, slug)
);

create index if not exists idx_project_skill_project
    on project_skill (project_uuid);

create index if not exists idx_project_skill_slug
    on project_skill (slug);

create index if not exists idx_project_skill_source
    on project_skill (source);

create index if not exists idx_project_skill_commit_sha
    on project_skill (commit_sha);

create index if not exists idx_project_skill_blob_hash
    on project_skill (blob_hash);

create table if not exists agent_task
(
    id           bigserial
        primary key,
    project_uuid uuid                                                          not null,
    parent_id    bigint
        constraint fk_agent_task_parent
            references agent_task
            on delete set null,
    agent_type   varchar(20)              default 'react'::character varying   not null,
    status       varchar(20)              default 'pending'::character varying not null,
    title        varchar(255),
    input        text                                                          not null,
    output       text,
    error        text,
    created_by   uuid,
    created_at   timestamp with time zone default now()                        not null,
    updated_at   timestamp with time zone default now()                        not null,
    started_at   timestamp with time zone,
    done_at      timestamp with time zone,
    progress     varchar(255),
    issue_id     uuid,
    retry_count  integer                  default 0
);

create index if not exists idx_agent_task_project
    on agent_task (project_uuid);

create index if not exists idx_agent_task_parent
    on agent_task (parent_id);

create index if not exists idx_agent_task_status
    on agent_task (status);

create index if not exists idx_agent_task_created_by
    on agent_task (created_by);

create index if not exists idx_agent_task_created_at
    on agent_task (created_at);

create index if not exists idx_agent_task_issue
    on agent_task (issue_id);

create index if not exists idx_agent_task_retry_count
    on agent_task (retry_count);

create table if not exists admin_user
(
    id            serial
        primary key,
    username      varchar(255)                           not null
        unique,
    password_hash varchar(255)                           not null,
    is_active     boolean                  default true  not null,
    created_at    timestamp with time zone default now() not null,
    updated_at    timestamp with time zone default now() not null
);

create index if not exists idx_admin_user_username
    on admin_user (username);

create table if not exists admin_role
(
    id          serial
        primary key,
    name        varchar(255)                           not null
        unique,
    description text,
    created_at  timestamp with time zone default now() not null
);

create table if not exists admin_permission
(
    id          serial
        primary key,
    name        varchar(255)                           not null,
    code        varchar(255)                           not null
        unique,
    description text,
    created_at  timestamp with time zone default now() not null
);

create table if not exists admin_user_role
(
    user_id integer not null
        references admin_user
            on delete cascade,
    role_id integer not null
        references admin_role
            on delete cascade,
    primary key (user_id, role_id)
);

create table if not exists admin_role_permission
(
    role_id       integer not null
        references admin_role
            on delete cascade,
    permission_id integer not null
        references admin_permission
            on delete cascade,
    primary key (role_id, permission_id)
);

create table if not exists admin_audit_log
(
    id             bigserial
        primary key,
    user_id        integer                                                       not null,
    username       varchar(255)                                                  not null,
    action         varchar(50)                                                   not null,
    resource       varchar(255)                                                  not null,
    resource_id    varchar(255),
    request_params jsonb,
    ip_address     varchar(255),
    user_agent     text,
    result         varchar(20)              default 'success'::character varying not null,
    error_message  text,
    created_at     timestamp with time zone default now()                        not null
);

create index if not exists idx_admin_audit_log_user_id
    on admin_audit_log (user_id);

create index if not exists idx_admin_audit_log_created_at
    on admin_audit_log (created_at desc);

create index if not exists idx_admin_audit_log_action
    on admin_audit_log (action);

create index if not exists idx_admin_audit_log_resource
    on admin_audit_log (resource);

create table if not exists admin_api_token
(
    id           serial
        primary key,
    name         varchar(255)                                  not null,
    token_hash   varchar(64)                                   not null
        unique,
    token_prefix varchar(32)                                   not null,
    permissions  text[]                   default '{}'::text[] not null,
    created_by   integer                                       not null
        references admin_user
            on delete set null,
    created_at   timestamp with time zone default now()        not null,
    last_used_at timestamp with time zone,
    expires_at   timestamp with time zone,
    is_active    boolean                  default true         not null
);

comment on table admin_api_token is 'Admin API Token for programmatic access';

create index if not exists idx_admin_api_token_hash
    on admin_api_token (token_hash);

create table if not exists workspace_alert_config
(
    id            serial
        primary key,
    workspace_id  uuid           not null,
    alert_type    varchar(32)    not null,
    threshold     numeric(10, 4) not null,
    email_enabled boolean                  default true,
    enabled       boolean                  default true,
    created_by    integer,
    created_at    timestamp with time zone default now(),
    updated_at    timestamp with time zone default now(),
    unique (workspace_id, alert_type)
);

create index if not exists idx_alert_config_workspace
    on workspace_alert_config (workspace_id);

create table if not exists room_attachment
(
    id           uuid                                   not null
        primary key,
    room         uuid                                   not null,
    message      uuid                                   not null,
    uploader     uuid                                   not null,
    file_name    varchar(255)                           not null,
    file_size    bigint                                 not null,
    content_type varchar(100)                           not null,
    s3_key       varchar(500)                           not null,
    created_at   timestamp with time zone default now() not null
);

create index if not exists idx_room_attachment_room
    on room_attachment (room);

create index if not exists idx_room_attachment_message
    on room_attachment (message);

create index if not exists idx_room_attachment_uploader
    on room_attachment (uploader);

create table if not exists room_access
(
    room       uuid                                   not null,
    "user"     uuid                                   not null,
    granted_by uuid                                   not null,
    granted_at timestamp with time zone default now() not null,
    primary key (room, "user")
);

create index if not exists idx_room_access_user
    on room_access ("user");

create table if not exists room_user_state
(
    room           uuid                  not null,
    "user"         uuid                  not null,
    last_read_seq  bigint,
    do_not_disturb boolean default false not null,
    dnd_start_hour smallint,
    dnd_end_hour   smallint,
    joined_at      timestamp with time zone,
    primary key (room, "user")
);

create index if not exists idx_room_user_state_user
    on room_user_state ("user");

create table if not exists project_role_priority
(
    id           bigserial
        primary key,
    project_uuid uuid                               not null,
    role_key     varchar(64)                        not null,
    display_name varchar(128)                       not null,
    priority     integer                  default 0 not null,
    color        varchar(32),
    created_at   timestamp with time zone default now(),
    updated_at   timestamp with time zone default now(),
    unique (project_uuid, role_key)
);

create index if not exists idx_project_role_priority_project
    on project_role_priority (project_uuid);

create index if not exists idx_project_role_priority_priority
    on project_role_priority (project_uuid, priority);

create table if not exists ai_conversation
(
    id                uuid                     default gen_random_uuid()           not null
        primary key,
    user_id           uuid                                                         not null,
    project_id        uuid
        constraint fk_ai_conv_project
            references project
            on delete cascade,
    scope             varchar(16)                                                  not null,
    title             varchar(512),
    model             varchar(128)             default 'gpt-4'::character varying  not null,
    model_config      jsonb,
    status            varchar(32)              default 'active'::character varying not null,
    root_message_id   uuid,
    fork_count        integer                  default 0                           not null,
    is_shared         boolean                  default false                       not null,
    message_count     integer                  default 0                           not null,
    token_usage_total integer,
    created_at        timestamp with time zone default now()                       not null,
    updated_at        timestamp with time zone default now()                       not null,
    access_visibility varchar(32)              default 'owner'::character varying  not null,
    can_ask           varchar(32)              default 'owner'::character varying  not null,
    project_uid       integer,
    model_uid         uuid,
    model_name        varchar(256)
);

create index if not exists idx_ai_conv_user_id
    on ai_conversation (user_id);

create index if not exists idx_ai_conv_project_id
    on ai_conversation (project_id);

create index if not exists idx_ai_conv_scope
    on ai_conversation (scope);

create index if not exists idx_ai_conv_user_created
    on ai_conversation (user_id asc, created_at desc);

create index if not exists idx_ai_conv_project_created
    on ai_conversation (project_id asc, created_at desc);

create index if not exists idx_ai_conv_access_vis
    on ai_conversation (access_visibility);

create index if not exists idx_ai_conv_project_uid
    on ai_conversation (project_id, project_uid)
    where (project_uid IS NOT NULL);

create table if not exists ai_message
(
    id                uuid                     default gen_random_uuid() not null
        primary key,
    conversation_id   uuid                                               not null
        constraint fk_ai_msg_conv
            references ai_conversation
            on delete cascade,
    parent_message_id uuid
        constraint fk_ai_msg_parent
            references ai_message
            on delete set null,
    role              varchar(16)                                        not null,
    content           jsonb                                              not null,
    model             varchar(128),
    is_fork_origin    boolean                  default false             not null,
    stop_reason       varchar(32),
    input_tokens      integer,
    output_tokens     integer,
    latency_ms        integer,
    metadata          jsonb,
    room_id           uuid,
    created_at        timestamp with time zone default now()             not null
);

create index if not exists idx_ai_msg_conv
    on ai_message (conversation_id, created_at);

create index if not exists idx_ai_msg_parent
    on ai_message (parent_message_id);

create table if not exists ai_message_fork
(
    id                uuid                     default gen_random_uuid() not null
        primary key,
    source_message_id uuid                                               not null
        constraint fk_ai_fork_source
            references ai_message
            on delete cascade,
    fork_message_id   uuid                                               not null
        constraint fk_ai_fork_fork
            references ai_message
            on delete cascade,
    created_at        timestamp with time zone default now()             not null
);

create index if not exists idx_ai_fork_source
    on ai_message_fork (source_message_id);

create index if not exists idx_ai_fork_fork
    on ai_message_fork (fork_message_id);

create table if not exists ai_shared_conversation
(
    id              uuid                     default gen_random_uuid() not null
        primary key,
    conversation_id uuid                                               not null
        constraint fk_ai_share_conv
            references ai_conversation
            on delete cascade,
    share_token     varchar(128)                                       not null
        unique,
    created_by      uuid                                               not null,
    view_count      integer                  default 0                 not null,
    created_at      timestamp with time zone default now()             not null,
    expires_at      timestamp with time zone
);

create index if not exists idx_ai_share_conv
    on ai_shared_conversation (conversation_id);

create index if not exists idx_ai_share_token
    on ai_shared_conversation (share_token);

create table if not exists ai_token_usage
(
    id              uuid                     default gen_random_uuid() not null
        primary key,
    user_id         uuid                                               not null,
    conversation_id uuid,
    model           varchar(128)                                       not null,
    input_tokens    integer                                            not null,
    output_tokens   integer                                            not null,
    cost_usd        numeric(10, 6),
    recorded_at     timestamp with time zone default now()             not null
);

create index if not exists idx_ai_token_user
    on ai_token_usage (user_id);

create index if not exists idx_ai_token_conv
    on ai_token_usage (conversation_id);

create index if not exists idx_ai_token_recorded
    on ai_token_usage (recorded_at);

