create extension if not exists "pgcrypto";

create table if not exists users (
    id uuid primary key default gen_random_uuid(),
    username text unique,
    email text unique not null,
    password_hash text not null,
    role text not null default 'user',
    full_name text not null,
    created_at timestamptz not null default now()
);

create table if not exists password_reset_tokens (
    id uuid primary key default gen_random_uuid(),
    user_id uuid not null references users(id) on delete cascade,
    token text unique not null,
    expires_at timestamptz not null,
    used_at timestamptz,
    created_at timestamptz not null default now()
);

create table if not exists role_categories (
    id uuid primary key default gen_random_uuid(),
    owner_id uuid references users(id) on delete cascade,
    name text not null,
    created_at timestamptz not null default now(),
    unique (owner_id, name)
);

create table if not exists app_config (
    key text primary key,
    value jsonb not null default '{}'::jsonb,
    updated_at timestamptz not null default now()
);

create table if not exists ansible_roles (
    id uuid primary key default gen_random_uuid(),
    owner_id uuid not null references users(id) on delete cascade,
    name text not null,
    source_type text not null,
    source_ref text not null default '',
    category_id uuid references role_categories(id) on delete set null,
    content jsonb not null default '{}'::jsonb,
    visibility text not null default 'personal' check (visibility in ('public', 'team', 'personal')),
    team_id uuid,
    forked_from_id uuid references ansible_roles(id) on delete set null,
    created_at timestamptz not null default now()
);

create table if not exists role_files (
    id uuid primary key default gen_random_uuid(),
    role_id uuid not null references ansible_roles(id) on delete cascade,
    path text not null,
    content text not null default '',
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now(),
    unique (role_id, path)
);

create table if not exists inventories (
    id uuid primary key default gen_random_uuid(),
    owner_id uuid not null references users(id) on delete cascade,
    name text not null,
    inventory_text text not null,
    created_at timestamptz not null default now()
);

create table if not exists playbooks (
    id uuid primary key default gen_random_uuid(),
    owner_id uuid not null references users(id) on delete cascade,
    name text not null,
    description text not null default '',
    playbook_yaml text not null,
    inventory_id uuid not null references inventories(id) on delete cascade,
    role_ids uuid[] not null default '{}',
    is_shared boolean not null default false,
    created_at timestamptz not null default now()
);

create table if not exists jobs (
    id uuid primary key default gen_random_uuid(),
    owner_id uuid not null references users(id) on delete cascade,
    playbook_id uuid not null references playbooks(id) on delete cascade,
    status text not null,
    runtime_mode text not null default 'docker',
    celery_task_id text,
    runner_url text,
    runner_run_id text,
    runner_container_name text,
    runner_last_heartbeat timestamptz,
    extra_vars jsonb not null default '{}'::jsonb,
    started_at timestamptz,
    finished_at timestamptz,
    created_at timestamptz not null default now()
);

create table if not exists job_logs (
    id bigserial primary key,
    job_id uuid not null references jobs(id) on delete cascade,
    log_line text not null,
    created_at timestamptz not null default now()
);

create table if not exists test_runs (
    id uuid primary key default gen_random_uuid(),
    owner_id uuid not null references users(id) on delete cascade,
    playbook_id uuid references playbooks(id) on delete cascade,
    role_id uuid references ansible_roles(id) on delete cascade,
    status text not null,
    runtime_mode text not null default 'docker',
    celery_task_id text,
    runner_url text,
    runner_run_id text,
    runner_container_name text,
    runner_last_heartbeat timestamptz,
    hosts_blueprint jsonb not null default '[]'::jsonb,
    extra_vars jsonb not null default '{}'::jsonb,
    started_at timestamptz,
    finished_at timestamptz,
    created_at timestamptz not null default now()
);

create table if not exists test_logs (
    id bigserial primary key,
    test_run_id uuid not null references test_runs(id) on delete cascade,
    log_line text not null,
    created_at timestamptz not null default now()
);
