CREATE TABLE IF NOT EXISTS users (
    id TEXT PRIMARY KEY,
    username TEXT NOT NULL UNIQUE,
    password_hash TEXT NOT NULL,
    display_name TEXT NOT NULL,
    role TEXT NOT NULL,
    status TEXT NOT NULL,
    permissions TEXT NOT NULL,
    create_time TEXT NOT NULL,
    last_login TEXT,
    protected INTEGER NOT NULL DEFAULT 0
);

CREATE TABLE IF NOT EXISTS models (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL UNIQUE,
    type TEXT NOT NULL,
    purpose TEXT NOT NULL,
    model_source TEXT NOT NULL,
    description TEXT,
    path TEXT,
    api_url TEXT,
    api_key TEXT,
    online_model_name TEXT,
    create_time TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS trained_models (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL UNIQUE,
    train_methods TEXT NOT NULL,
    base_model_path TEXT,
    create_time TEXT NOT NULL,
    merged INTEGER NOT NULL DEFAULT 0,
    merging INTEGER NOT NULL DEFAULT 0,
    merged_path TEXT
);

CREATE TABLE IF NOT EXISTS datasets (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL UNIQUE,
    type TEXT NOT NULL,
    storage_type TEXT NOT NULL,
    source TEXT NOT NULL,
    task_id TEXT,
    size TEXT,
    count INTEGER NOT NULL DEFAULT 0,
    description TEXT,
    create_time TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS dataset_files (
    id TEXT PRIMARY KEY,
    dataset_id TEXT NOT NULL REFERENCES datasets(id) ON DELETE CASCADE,
    name TEXT NOT NULL,
    size TEXT,
    content TEXT NOT NULL,
    active_version_id TEXT NOT NULL,
    versions TEXT NOT NULL,
    create_time TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS compute_nodes (
    id TEXT PRIMARY KEY,
    code TEXT NOT NULL UNIQUE,
    name TEXT NOT NULL,
    api_base_url TEXT NOT NULL,
    file_gateway_url TEXT NOT NULL,
    enabled INTEGER NOT NULL DEFAULT 1,
    scheduler_status TEXT NOT NULL,
    scheduler_weight INTEGER NOT NULL DEFAULT 100,
    tags TEXT NOT NULL,
    gpu_count INTEGER NOT NULL DEFAULT 0,
    current_running_jobs INTEGER NOT NULL DEFAULT 0,
    max_parallel_jobs INTEGER NOT NULL DEFAULT 2,
    data_root TEXT NOT NULL,
    model_root TEXT NOT NULL,
    log_root TEXT NOT NULL,
    last_health_check_at TEXT,
    health_detail TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS gpus (
    id TEXT PRIMARY KEY,
    node_id TEXT NOT NULL REFERENCES compute_nodes(id) ON DELETE CASCADE,
    gpu_index INTEGER NOT NULL,
    uuid TEXT NOT NULL,
    name TEXT NOT NULL,
    memory_total_gb DOUBLE PRECISION NOT NULL,
    power_limit_w DOUBLE PRECISION NOT NULL,
    base_temperature INTEGER NOT NULL
);

CREATE TABLE IF NOT EXISTS fine_tune_tasks (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL UNIQUE,
    payload TEXT NOT NULL,
    status TEXT NOT NULL,
    progress INTEGER NOT NULL DEFAULT 0,
    process_id INTEGER,
    create_time TEXT NOT NULL,
    start_time TEXT,
    completed_at TEXT,
    compute_node_id TEXT REFERENCES compute_nodes(id) ON DELETE SET NULL,
    gpus TEXT NOT NULL,
    sync_job_id TEXT
);

CREATE TABLE IF NOT EXISTS resource_replicas (
    id TEXT PRIMARY KEY,
    node_id TEXT NOT NULL REFERENCES compute_nodes(id) ON DELETE CASCADE,
    resource_type TEXT NOT NULL,
    resource_id TEXT NOT NULL,
    local_path TEXT NOT NULL,
    status TEXT NOT NULL,
    sync_status TEXT NOT NULL,
    create_time TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS resource_sync_jobs (
    id TEXT PRIMARY KEY,
    target_node_id TEXT NOT NULL,
    resources TEXT NOT NULL,
    status TEXT NOT NULL,
    progress INTEGER NOT NULL DEFAULT 0,
    create_time TEXT NOT NULL,
    completed_at TEXT
);

-- ===================== Project / Tenant =====================

CREATE TABLE IF NOT EXISTS projects (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL DEFAULT 'default',
    name TEXT NOT NULL,
    code TEXT NOT NULL,
    description TEXT,
    quota TEXT,
    status TEXT NOT NULL DEFAULT 'active',
    create_time TEXT NOT NULL,
    create_by TEXT,
    updated_at TEXT
);

CREATE TABLE IF NOT EXISTS project_members (
    project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    role TEXT NOT NULL DEFAULT 'member',
    create_time TEXT NOT NULL,
    PRIMARY KEY (project_id, user_id)
);

-- ===================== Fine-tune Checkpoints =====================

CREATE TABLE IF NOT EXISTS fine_tune_checkpoints (
    id TEXT PRIMARY KEY,
    task_id TEXT NOT NULL REFERENCES fine_tune_tasks(id) ON DELETE CASCADE,
    name TEXT NOT NULL,
    path TEXT NOT NULL,
    step INTEGER NOT NULL DEFAULT 0,
    loss DOUBLE PRECISION,
    is_best INTEGER NOT NULL DEFAULT 0,
    size_bytes BIGINT DEFAULT 0,
    create_time TEXT NOT NULL
);

-- ===================== Compute Jobs (internal) =====================

CREATE TABLE IF NOT EXISTS compute_jobs (
    id TEXT PRIMARY KEY,
    task_id TEXT NOT NULL REFERENCES fine_tune_tasks(id) ON DELETE CASCADE,
    node_id TEXT NOT NULL,
    name TEXT NOT NULL,
    type TEXT NOT NULL DEFAULT 'train',
    status TEXT NOT NULL DEFAULT 'pending',
    command TEXT,
    gpu_count INTEGER NOT NULL DEFAULT 1,
    priority INTEGER NOT NULL DEFAULT 0,
    timeout_seconds INTEGER,
    progress REAL DEFAULT 0,
    result TEXT,
    error_message TEXT,
    create_time TEXT NOT NULL,
    start_time TEXT,
    completed_at TEXT
);

-- ===================== Indexes =====================

CREATE INDEX IF NOT EXISTS idx_fine_tune_status ON fine_tune_tasks(status);
CREATE INDEX IF NOT EXISTS idx_dataset_files_dataset ON dataset_files(dataset_id);
CREATE INDEX IF NOT EXISTS idx_gpus_node ON gpus(node_id);
CREATE INDEX IF NOT EXISTS idx_replicas_resource ON resource_replicas(resource_type, resource_id);
CREATE INDEX IF NOT EXISTS idx_projects_tenant ON projects(tenant_id);
CREATE INDEX IF NOT EXISTS idx_project_members_user ON project_members(user_id);
CREATE INDEX IF NOT EXISTS idx_checkpoints_task ON fine_tune_checkpoints(task_id);
CREATE INDEX IF NOT EXISTS idx_compute_jobs_task ON compute_jobs(task_id);
CREATE INDEX IF NOT EXISTS idx_compute_jobs_node ON compute_jobs(node_id);
CREATE INDEX IF NOT EXISTS idx_compute_jobs_status ON compute_jobs(status);

-- ===================== Migrations: extend fine_tune_tasks =====================

ALTER TABLE fine_tune_tasks ADD COLUMN IF NOT EXISTS project_id TEXT;
ALTER TABLE fine_tune_tasks ADD COLUMN IF NOT EXISTS tenant_id TEXT NOT NULL DEFAULT 'default';
ALTER TABLE fine_tune_tasks ADD COLUMN IF NOT EXISTS dataset_name TEXT;
ALTER TABLE fine_tune_tasks ADD COLUMN IF NOT EXISTS model_name TEXT;
ALTER TABLE fine_tune_tasks ADD COLUMN IF NOT EXISTS trained_model_name TEXT;
ALTER TABLE fine_tune_tasks ADD COLUMN IF NOT EXISTS checkpoint_retention_policy TEXT;
ALTER TABLE fine_tune_tasks ADD COLUMN IF NOT EXISTS error_message TEXT;
ALTER TABLE fine_tune_tasks ADD COLUMN IF NOT EXISTS retry_count INTEGER NOT NULL DEFAULT 0;
ALTER TABLE fine_tune_tasks ADD COLUMN IF NOT EXISTS last_retry_at TEXT;
ALTER TABLE fine_tune_tasks ADD COLUMN IF NOT EXISTS resumed_from_checkpoint_id TEXT;

CREATE INDEX IF NOT EXISTS idx_fine_tune_project ON fine_tune_tasks(project_id);
