CREATE TABLE achievements (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    slug        TEXT UNIQUE NOT NULL,
    title       TEXT NOT NULL,
    icon        TEXT NOT NULL DEFAULT '🏆',
    category    TEXT NOT NULL DEFAULT 'general',
    description TEXT
  );

CREATE TABLE admin_audit_log (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    admin_id   INTEGER NOT NULL REFERENCES users(id),
    action     TEXT NOT NULL,
    target     TEXT,
    detail     TEXT,
    ip         TEXT,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE announcements (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    class_id   INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE,
    author_id  INTEGER NOT NULL REFERENCES users(id)   ON DELETE CASCADE,
    text       TEXT NOT NULL,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE app_settings (
    key   TEXT PRIMARY KEY,
    value TEXT NOT NULL DEFAULT ''
  );

CREATE TABLE "assignment_sessions" (
        id            INTEGER PRIMARY KEY AUTOINCREMENT,
        assignment_id INTEGER NOT NULL REFERENCES assignments(id) ON DELETE CASCADE,
        user_id       INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        session_id    INTEGER REFERENCES test_sessions(id) ON DELETE SET NULL,
        attempt_num   INTEGER NOT NULL DEFAULT 1,
        first_seen_at TEXT
      );

CREATE TABLE assignment_templates (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    created_by   INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    label        TEXT NOT NULL,
    subject_slug TEXT NOT NULL,
    mode         TEXT NOT NULL DEFAULT 'exam',
    count        INTEGER NOT NULL DEFAULT 25,
    topic_id     INTEGER REFERENCES topics(id) ON DELETE SET NULL,
    test_id      INTEGER REFERENCES tests(id)  ON DELETE SET NULL,
    file_id      INTEGER REFERENCES files(id)  ON DELETE SET NULL,
    is_homework  INTEGER NOT NULL DEFAULT 0,
    created_at   TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE "assignments" (
        id           INTEGER PRIMARY KEY AUTOINCREMENT,
        class_id     INTEGER REFERENCES classes(id) ON DELETE CASCADE,
        user_id      INTEGER REFERENCES users(id)   ON DELETE CASCADE,
        title        TEXT NOT NULL,
        subject_slug TEXT NOT NULL,
        mode         TEXT NOT NULL DEFAULT 'exam',
        count        INTEGER NOT NULL DEFAULT 25,
        topic_id     INTEGER REFERENCES topics(id) ON DELETE SET NULL,
        deadline     TEXT,
        created_by   INTEGER NOT NULL REFERENCES users(id),
        test_id      INTEGER REFERENCES tests(id) ON DELETE SET NULL,
        created_at   TEXT NOT NULL DEFAULT (datetime('now'))
      , file_id INTEGER REFERENCES files(id) ON DELETE SET NULL, is_homework INTEGER NOT NULL DEFAULT 0, max_attempts INTEGER NOT NULL DEFAULT 0);

CREATE TABLE avatar_requests (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id     INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    filename    TEXT    NOT NULL,
    status      TEXT    NOT NULL DEFAULT 'pending',
    reviewer_id INTEGER REFERENCES users(id),
    reject_msg  TEXT,
    created_at  TEXT    NOT NULL DEFAULT (datetime('now')),
    reviewed_at TEXT
  );

CREATE TABLE bio_challenges (
    id             INTEGER PRIMARY KEY AUTOINCREMENT,
    title          TEXT NOT NULL,
    description    TEXT NOT NULL DEFAULT '',
    type           TEXT NOT NULL DEFAULT 'build',
    target_formula TEXT NOT NULL DEFAULT '',
    hint           TEXT DEFAULT NULL,
    xp_reward      INTEGER NOT NULL DEFAULT 50,
    difficulty     INTEGER NOT NULL DEFAULT 1,
    topic_tag      TEXT DEFAULT NULL,
    order_n        INTEGER NOT NULL DEFAULT 0
  , data_json TEXT DEFAULT NULL);

CREATE TABLE bio_elements (
    symbol       TEXT PRIMARY KEY,
    name_ru      TEXT NOT NULL,
    valency_max  INTEGER NOT NULL DEFAULT 1,
    valency_opts TEXT NOT NULL DEFAULT '[1]',
    color        TEXT NOT NULL DEFAULT '#888888',
    radius       INTEGER NOT NULL DEFAULT 20,
    mass         REAL NOT NULL DEFAULT 1.0
  );

CREATE TABLE bio_molecules (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    formula     TEXT NOT NULL,
    name_ru     TEXT NOT NULL,
    name_lat    TEXT NOT NULL DEFAULT '',
    category    TEXT NOT NULL DEFAULT 'inorganic',
    difficulty  INTEGER NOT NULL DEFAULT 1,
    description TEXT NOT NULL DEFAULT '',
    atoms_json  TEXT NOT NULL DEFAULT '[]',
    bonds_json  TEXT NOT NULL DEFAULT '[]',
    is_library  INTEGER NOT NULL DEFAULT 1,
    topic_tags  TEXT NOT NULL DEFAULT '[]',
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE bio_reactions (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    equation     TEXT NOT NULL,
    name_ru      TEXT NOT NULL,
    type         TEXT NOT NULL DEFAULT 'synthesis',
    description  TEXT NOT NULL DEFAULT '',
    reactant_ids TEXT NOT NULL DEFAULT '[]',
    product_ids  TEXT NOT NULL DEFAULT '[]',
    conditions   TEXT DEFAULT NULL,
    energy_kj    REAL DEFAULT NULL,
    topic_tags   TEXT NOT NULL DEFAULT '[]'
  );

CREATE TABLE bio_user_challenges (
    user_id      INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    challenge_id INTEGER NOT NULL REFERENCES bio_challenges(id) ON DELETE CASCADE,
    completed_at TEXT NOT NULL DEFAULT (datetime('now')),
    PRIMARY KEY (user_id, challenge_id)
  );

CREATE TABLE bio_user_molecules (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id     INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    molecule_id INTEGER REFERENCES bio_molecules(id),
    name        TEXT DEFAULT NULL,
    formula     TEXT NOT NULL,
    atoms_json  TEXT NOT NULL,
    bonds_json  TEXT NOT NULL,
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE bookmarks (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id     INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    entity_type TEXT NOT NULL CHECK (entity_type IN ('lesson','course','file','question')),
    entity_id   INTEGER NOT NULL,
    created_at  TEXT NOT NULL DEFAULT (datetime('now')),
    UNIQUE (user_id, entity_type, entity_id)
  );

CREATE TABLE challenges (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id     INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    week        TEXT NOT NULL,
    title       TEXT NOT NULL,
    description TEXT,
    type        TEXT NOT NULL DEFAULT 'tests',
    target      INTEGER NOT NULL DEFAULT 3,
    progress    INTEGER NOT NULL DEFAULT 0,
    xp_reward   INTEGER NOT NULL DEFAULT 100,
    subject_slug TEXT,
    topic_id    INTEGER,
    completed   INTEGER NOT NULL DEFAULT 0,
    claimed     INTEGER NOT NULL DEFAULT 0,
    UNIQUE(user_id, week, title)
  );

CREATE TABLE class_courses (
    class_id    INTEGER NOT NULL REFERENCES classes(id)  ON DELETE CASCADE,
    course_id   INTEGER NOT NULL REFERENCES courses(id)  ON DELETE CASCADE,
    deadline    TEXT,
    assigned_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
    assigned_at TEXT NOT NULL DEFAULT (datetime('now')),
    PRIMARY KEY (class_id, course_id)
  );

CREATE TABLE class_members (
    id        INTEGER PRIMARY KEY AUTOINCREMENT,
    class_id  INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE,
    user_id   INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    joined_at TEXT NOT NULL DEFAULT (datetime('now')),
    UNIQUE (class_id, user_id)
  );

CREATE TABLE classes (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    name        TEXT NOT NULL,
    description TEXT,
    teacher_id  INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    invite_code TEXT UNIQUE NOT NULL,
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
  , features TEXT, cover_emoji TEXT NOT NULL DEFAULT '');

CREATE TABLE classroom_attendance (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE,
    user_id    INTEGER NOT NULL REFERENCES users(id),
    joined_at  TEXT NOT NULL DEFAULT (datetime('now')),
    left_at    TEXT,
    UNIQUE(session_id, user_id)
  );

CREATE TABLE classroom_chat (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE,
    user_id    INTEGER NOT NULL REFERENCES users(id),
    message    TEXT NOT NULL,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  , pinned INTEGER NOT NULL DEFAULT 0, attachment_url  TEXT, attachment_type TEXT);

CREATE TABLE classroom_chat_reactions (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    chat_id    INTEGER NOT NULL REFERENCES classroom_chat(id) ON DELETE CASCADE,
    user_id    INTEGER NOT NULL REFERENCES users(id),
    reaction   TEXT    NOT NULL,
    created_at TEXT    NOT NULL DEFAULT (datetime('now')),
    UNIQUE(chat_id, user_id, reaction)
  );

CREATE TABLE classroom_draw_permissions (
    session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE,
    user_id    INTEGER NOT NULL REFERENCES users(id),
    PRIMARY KEY (session_id, user_id)
  );

CREATE TABLE classroom_hands (
    session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE,
    user_id    INTEGER NOT NULL REFERENCES users(id),
    PRIMARY KEY (session_id, user_id)
  );

CREATE TABLE classroom_invites (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE,
    user_id    INTEGER NOT NULL REFERENCES users(id),
    UNIQUE(session_id, user_id)
  );

CREATE TABLE classroom_notes (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE,
    user_id    INTEGER NOT NULL REFERENCES users(id),
    content    TEXT    NOT NULL DEFAULT '',
    updated_at TEXT    NOT NULL DEFAULT (datetime('now')),
    UNIQUE(session_id, user_id)
  );

CREATE TABLE classroom_pages (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE,
    page_num   INTEGER NOT NULL DEFAULT 1,
    bg_color   TEXT NOT NULL DEFAULT '#ffffff', template TEXT NOT NULL DEFAULT 'blank', name TEXT,
    UNIQUE(session_id, page_num)
  );

CREATE TABLE classroom_sessions (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    class_id     INTEGER REFERENCES classes(id) ON DELETE CASCADE,
    teacher_id   INTEGER NOT NULL REFERENCES users(id),
    title        TEXT NOT NULL DEFAULT '',
    status       TEXT NOT NULL DEFAULT 'active',
    current_page INTEGER NOT NULL DEFAULT 1,
    created_at   TEXT NOT NULL DEFAULT (datetime('now')),
    ended_at     TEXT
  , board_theme TEXT NOT NULL DEFAULT 'chalkboard');

CREATE TABLE classroom_strokes (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id INTEGER NOT NULL REFERENCES classroom_sessions(id) ON DELETE CASCADE,
    page_num   INTEGER NOT NULL DEFAULT 1,
    user_id    INTEGER NOT NULL REFERENCES users(id),
    tool       TEXT NOT NULL DEFAULT 'pencil',
    data       TEXT NOT NULL,
    seq        INTEGER NOT NULL,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE classroom_templates (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    teacher_id  INTEGER NOT NULL REFERENCES users(id),
    title       TEXT    NOT NULL,
    description TEXT    DEFAULT '',
    pages_data  TEXT    NOT NULL DEFAULT '[]',
    created_at  TEXT    NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE course_sections (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    course_id   INTEGER NOT NULL REFERENCES courses(id) ON DELETE CASCADE,
    title       TEXT NOT NULL,
    order_index INTEGER NOT NULL DEFAULT 0
  );

CREATE TABLE course_templates (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    title       TEXT NOT NULL,
    description TEXT,
    category    TEXT NOT NULL DEFAULT 'general',
    subject_slug TEXT,
    structure   TEXT NOT NULL DEFAULT '{}',
    is_public   INTEGER NOT NULL DEFAULT 0,
    created_by  INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE courses (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    subject_slug TEXT NOT NULL,
    title        TEXT NOT NULL,
    description  TEXT,
    cover_emoji  TEXT NOT NULL DEFAULT '📚',
    order_index  INTEGER NOT NULL DEFAULT 0,
    is_published INTEGER NOT NULL DEFAULT 0,
    created_by   INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    created_at   TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE daily_goals (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id      INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    date         TEXT NOT NULL,
    tests_target INTEGER NOT NULL DEFAULT 3,
    tests_done   INTEGER NOT NULL DEFAULT 0,
    xp_target    INTEGER NOT NULL DEFAULT 200,
    xp_earned    INTEGER NOT NULL DEFAULT 0,
    UNIQUE (user_id, date)
  );

CREATE TABLE error_log (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    level      TEXT NOT NULL DEFAULT 'error',
    message    TEXT NOT NULL,
    stack      TEXT,
    route      TEXT,
    method     TEXT,
    user_id    INTEGER,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE file_access (
    id        INTEGER PRIMARY KEY AUTOINCREMENT,
    file_id   INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,
    type      TEXT NOT NULL CHECK (type IN ('class', 'user')),
    target_id INTEGER NOT NULL,
    UNIQUE (file_id, type, target_id)
  );

CREATE TABLE files (
    id            INTEGER PRIMARY KEY AUTOINCREMENT,
    title         TEXT NOT NULL,
    description   TEXT,
    original_name TEXT NOT NULL,
    stored_name   TEXT NOT NULL UNIQUE,
    mimetype      TEXT,
    size          INTEGER,
    subject_slug  TEXT,
    is_public     INTEGER NOT NULL DEFAULT 1,
    uploaded_by   INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    created_at    TEXT NOT NULL DEFAULT (datetime('now'))
  , folder_id INTEGER);

CREATE TABLE flashcard_cards (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    deck_id    INTEGER NOT NULL REFERENCES flashcard_decks(id) ON DELETE CASCADE,
    front      TEXT NOT NULL DEFAULT '',
    back       TEXT NOT NULL DEFAULT '',
    order_idx  INTEGER NOT NULL DEFAULT 0,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE flashcard_decks (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id     INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    title       TEXT NOT NULL,
    description TEXT NOT NULL DEFAULT '',
    color       TEXT NOT NULL DEFAULT '#9B5DE5',
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE flashcard_reviews (
    id            INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id       INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    card_id       INTEGER NOT NULL REFERENCES flashcard_cards(id) ON DELETE CASCADE,
    ease_factor   REAL NOT NULL DEFAULT 2.5,
    interval_days INTEGER NOT NULL DEFAULT 1,
    repetitions   INTEGER NOT NULL DEFAULT 0,
    due_at        TEXT NOT NULL DEFAULT (datetime('now')),
    last_reviewed TEXT,
    UNIQUE(user_id, card_id)
  );

CREATE TABLE folder_access (
    id        INTEGER PRIMARY KEY AUTOINCREMENT,
    folder_id INTEGER NOT NULL REFERENCES folders(id) ON DELETE CASCADE,
    type      TEXT NOT NULL CHECK (type IN ('class', 'user')),
    target_id INTEGER NOT NULL,
    UNIQUE (folder_id, type, target_id)
  );

CREATE TABLE folders (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    name       TEXT NOT NULL,
    created_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE geometry_submissions (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    task_id     INTEGER NOT NULL REFERENCES geometry_tasks(id) ON DELETE CASCADE,
    student_id  INTEGER NOT NULL REFERENCES users(id),
    state_json  TEXT    NOT NULL DEFAULT '{}',
    score       REAL    DEFAULT NULL,
    feedback    TEXT    DEFAULT '',
    submitted_at TEXT   NOT NULL DEFAULT (datetime('now')),
    UNIQUE(task_id, student_id)
  );

CREATE TABLE geometry_tasks (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    teacher_id  INTEGER NOT NULL REFERENCES users(id),
    class_id    INTEGER REFERENCES classes(id) ON DELETE SET NULL,
    title       TEXT    NOT NULL DEFAULT 'Без названия',
    description TEXT    DEFAULT '',
    state_json  TEXT    NOT NULL DEFAULT '{}',
    created_at  TEXT    NOT NULL DEFAULT (datetime('now')),
    updated_at  TEXT    NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE "lesson_blocks" (
      id          INTEGER PRIMARY KEY AUTOINCREMENT,
      lesson_id   INTEGER NOT NULL REFERENCES lessons(id) ON DELETE CASCADE,
      type        TEXT NOT NULL DEFAULT 'text'
                  CHECK (type IN ('heading','text','formula','image','quiz','sim',
                                  'table','code','divider','callout','video','flashcard',
                                  'matching','fill-blank','ordering',
                                  'accordion','timeline','diagram','geogebra','audio','columns','alert')),
      order_index INTEGER NOT NULL DEFAULT 0,
      data        TEXT NOT NULL DEFAULT '{}'
    );

CREATE TABLE lesson_comments (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    lesson_id  INTEGER NOT NULL REFERENCES lessons(id) ON DELETE CASCADE,
    user_id    INTEGER NOT NULL REFERENCES users(id)   ON DELETE CASCADE,
    parent_id  INTEGER REFERENCES lesson_comments(id)  ON DELETE CASCADE,
    text       TEXT NOT NULL,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE lesson_notes (
    user_id     INTEGER NOT NULL REFERENCES users(id)   ON DELETE CASCADE,
    lesson_id   INTEGER NOT NULL REFERENCES lessons(id) ON DELETE CASCADE,
    text        TEXT NOT NULL DEFAULT '',
    updated_at  TEXT NOT NULL DEFAULT (datetime('now')),
    PRIMARY KEY (user_id, lesson_id)
  );

CREATE TABLE lesson_progress (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id     INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    lesson_id   INTEGER NOT NULL REFERENCES lessons(id) ON DELETE CASCADE,
    completed   INTEGER NOT NULL DEFAULT 0,
    updated_at  TEXT NOT NULL DEFAULT (datetime('now')),
    UNIQUE (user_id, lesson_id)
  );

CREATE TABLE lesson_templates (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    title       TEXT NOT NULL,
    category    TEXT NOT NULL DEFAULT 'general',
    subject_slug TEXT,
    blocks      TEXT NOT NULL DEFAULT '[]',
    is_public   INTEGER NOT NULL DEFAULT 0,
    created_by  INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE lessons (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    course_id    INTEGER NOT NULL REFERENCES courses(id) ON DELETE CASCADE,
    title        TEXT NOT NULL,
    order_index  INTEGER NOT NULL DEFAULT 0,
    is_published INTEGER NOT NULL DEFAULT 0,
    created_at   TEXT NOT NULL DEFAULT (datetime('now'))
  , section_id INTEGER REFERENCES course_sections(id) ON DELETE SET NULL, read_time  INTEGER NOT NULL DEFAULT 0);

CREATE TABLE "live_answers" (
        id               INTEGER PRIMARY KEY AUTOINCREMENT,
        live_session_id  INTEGER NOT NULL REFERENCES live_sessions(id) ON DELETE CASCADE,
        user_id          INTEGER NOT NULL REFERENCES users(id),
        question_id      INTEGER REFERENCES questions(id) ON DELETE SET NULL,
        option_id        INTEGER REFERENCES options(id),
        answer_text      TEXT,
        is_correct       INTEGER,
        answered_at      TEXT NOT NULL DEFAULT (datetime('now')),
        UNIQUE(live_session_id, user_id, question_id)
      );

CREATE TABLE live_sessions (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    class_id    INTEGER NOT NULL REFERENCES classes(id)    ON DELETE CASCADE,
    teacher_id  INTEGER NOT NULL REFERENCES users(id),
    question_id INTEGER          REFERENCES questions(id),
    status      TEXT    NOT NULL DEFAULT 'waiting',
    show_results INTEGER NOT NULL DEFAULT 0,
    created_at  TEXT    NOT NULL DEFAULT (datetime('now')),
    ended_at    TEXT
  );

CREATE TABLE notifications (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id    INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    type       TEXT NOT NULL DEFAULT 'info',
    message    TEXT NOT NULL,
    link       TEXT,
    is_read    INTEGER NOT NULL DEFAULT 0,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE options (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    question_id INTEGER NOT NULL REFERENCES questions(id) ON DELETE CASCADE,
    text        TEXT NOT NULL,
    is_correct  INTEGER NOT NULL DEFAULT 0,
    order_index INTEGER NOT NULL DEFAULT 0
  , match_pair TEXT);

CREATE TABLE parent_links (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    student_id  INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    token       TEXT UNIQUE NOT NULL,
    label       TEXT NOT NULL DEFAULT '',
    is_active   INTEGER NOT NULL DEFAULT 1,
    last_used   TEXT,
    created_at  TEXT NOT NULL DEFAULT (datetime('now')),
    expires_at  TEXT
  );

CREATE TABLE parent_notifications (
    id             INTEGER PRIMARY KEY AUTOINCREMENT,
    parent_link_id INTEGER NOT NULL REFERENCES parent_links(id) ON DELETE CASCADE,
    type           TEXT NOT NULL DEFAULT 'info',
    message        TEXT NOT NULL,
    is_read        INTEGER NOT NULL DEFAULT 0,
    created_at     TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE questions (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    subject_id  INTEGER NOT NULL REFERENCES subjects(id) ON DELETE CASCADE,
    topic_id    INTEGER REFERENCES topics(id) ON DELETE SET NULL,
    text        TEXT NOT NULL,
    difficulty  INTEGER NOT NULL DEFAULT 1 CHECK (difficulty BETWEEN 1 AND 3),
    year        INTEGER,
    explanation TEXT,
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
  , type TEXT NOT NULL DEFAULT 'single', correct_text TEXT, image TEXT, source_type TEXT NOT NULL DEFAULT 'базовый');

CREATE TABLE rb_food_web (
    predator_id INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE,
    prey_id     INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE,
    strength    REAL    NOT NULL DEFAULT 0.5,
    PRIMARY KEY (predator_id, prey_id)
  );

CREATE TABLE rb_groups (
    id       INTEGER PRIMARY KEY AUTOINCREMENT,
    name_ru  TEXT NOT NULL,
    name_lat TEXT NOT NULL DEFAULT '',
    icon     TEXT NOT NULL DEFAULT '🌿',
    color    TEXT NOT NULL DEFAULT '#16a34a'
  );

CREATE TABLE rb_habitats (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    name        TEXT NOT NULL,
    type        TEXT NOT NULL DEFAULT 'forest',
    description TEXT NOT NULL DEFAULT '',
    sound_file  TEXT NOT NULL DEFAULT ''
  );

CREATE TABLE rb_population_data (
    id             INTEGER PRIMARY KEY AUTOINCREMENT,
    species_id     INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE,
    year           INTEGER NOT NULL,
    count_estimate INTEGER NOT NULL DEFAULT 0,
    source         TEXT    NOT NULL DEFAULT ''
  );

CREATE TABLE rb_quests (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    title       TEXT    NOT NULL,
    description TEXT    NOT NULL DEFAULT '',
    species_ids TEXT    NOT NULL DEFAULT '[]',
    xp_reward   INTEGER NOT NULL DEFAULT 150,
    badge_slug  TEXT    NOT NULL DEFAULT ''
  );

CREATE TABLE rb_sightings (
    id                  INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id             INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    species_id          INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE,
    region_code         TEXT    NOT NULL DEFAULT '',
    description         TEXT    NOT NULL DEFAULT '',
    photo_url           TEXT    NOT NULL DEFAULT '',
    confirmed_by_teacher INTEGER NOT NULL DEFAULT 0,
    created_at          TEXT    NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE rb_species (
    id                  INTEGER PRIMARY KEY AUTOINCREMENT,
    group_id            INTEGER NOT NULL REFERENCES rb_groups(id),
    habitat_id          INTEGER REFERENCES rb_habitats(id),
    name_ru             TEXT NOT NULL,
    name_be             TEXT NOT NULL DEFAULT '',
    name_lat            TEXT NOT NULL DEFAULT '',
    category            TEXT NOT NULL DEFAULT 'VU'
                        CHECK (category IN ('CR','EN','VU','NT','LC')),
    by_category         TEXT NOT NULL DEFAULT 'III',
    description         TEXT NOT NULL DEFAULT '',
    interesting_fact    TEXT NOT NULL DEFAULT '',
    threats             TEXT NOT NULL DEFAULT '[]',
    conservation        TEXT NOT NULL DEFAULT '',
    where_to_see        TEXT NOT NULL DEFAULT '',
    photo_url           TEXT NOT NULL DEFAULT '',
    model_type          TEXT NOT NULL DEFAULT 'silhouette'
                        CHECK (model_type IN ('procedural','silhouette','none')),
    population_trend    TEXT NOT NULL DEFAULT '[]',
    biomass_kg          REAL NOT NULL DEFAULT 0,
    created_at          TEXT NOT NULL DEFAULT (datetime('now'))
  , season_active TEXT NOT NULL DEFAULT '', name_be_short TEXT NOT NULL DEFAULT '');

CREATE TABLE rb_species_regions (
    species_id  INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE,
    region_code TEXT NOT NULL
                CHECK (region_code IN ('brest','vitebsk','gomel','grodno','minsk','mogilev')),
    PRIMARY KEY (species_id, region_code)
  );

CREATE TABLE rb_user_collection (
    user_id       INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    species_id    INTEGER NOT NULL REFERENCES rb_species(id) ON DELETE CASCADE,
    unlock_method TEXT    NOT NULL DEFAULT 'explore',
    notes         TEXT    NOT NULL DEFAULT '',
    unlocked_at   TEXT    NOT NULL DEFAULT (datetime('now')),
    PRIMARY KEY (user_id, species_id)
  );

CREATE TABLE rb_user_quests (
    user_id      INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    quest_id     INTEGER NOT NULL REFERENCES rb_quests(id) ON DELETE CASCADE,
    status       TEXT    NOT NULL DEFAULT 'active'
                 CHECK (status IN ('active','completed')),
    progress     TEXT    NOT NULL DEFAULT '{}',
    completed_at TEXT,
    PRIMARY KEY (user_id, quest_id)
  );

CREATE TABLE "role_permissions" (
      id         INTEGER PRIMARY KEY AUTOINCREMENT,
      role       TEXT NOT NULL CHECK (role IN ('teacher', 'student', 'free_student')),
      permission TEXT NOT NULL,
      enabled    INTEGER NOT NULL DEFAULT 0,
      UNIQUE (role, permission)
    );

CREATE TABLE session_questions (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id  INTEGER NOT NULL REFERENCES test_sessions(id) ON DELETE CASCADE,
    question_id INTEGER NOT NULL REFERENCES questions(id),
    order_index INTEGER NOT NULL
  );

CREATE TABLE shop_items (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    name        TEXT NOT NULL,
    description TEXT,
    type        TEXT NOT NULL DEFAULT 'frame'
                CHECK (type IN ('frame','theme','title','effect')),
    category    TEXT NOT NULL DEFAULT 'cosmetic',
    price       INTEGER NOT NULL DEFAULT 100,
    data        TEXT NOT NULL DEFAULT '{}',
    icon        TEXT NOT NULL DEFAULT 'star',
    is_active   INTEGER NOT NULL DEFAULT 1,
    created_at  TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE subjects (
    id   INTEGER PRIMARY KEY AUTOINCREMENT,
    slug TEXT UNIQUE NOT NULL,
    name TEXT NOT NULL,
    icon TEXT
  , default_mode  TEXT NOT NULL DEFAULT 'exam', default_count INTEGER NOT NULL DEFAULT 25, default_test_id INTEGER REFERENCES tests(id) ON DELETE SET NULL);

CREATE TABLE submission_log (
    id              INTEGER PRIMARY KEY AUTOINCREMENT,
    submission_id   INTEGER NOT NULL,
    class_id        INTEGER,
    assignment_id   INTEGER,
    student_id      INTEGER NOT NULL,
    student_name    TEXT,
    original_name   TEXT,
    status          TEXT,
    grade           INTEGER,
    teacher_note    TEXT,
    submitted_at    TEXT,
    action          TEXT NOT NULL DEFAULT 'deleted',
    deleted_by      INTEGER NOT NULL,
    deleted_by_role TEXT,
    deleted_at      TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE "submissions" (
      id            INTEGER PRIMARY KEY AUTOINCREMENT,
      class_id      INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE,
      assignment_id INTEGER REFERENCES assignments(id) ON DELETE SET NULL,
      student_id    INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
      original_name TEXT NOT NULL,
      stored_name   TEXT NOT NULL UNIQUE,
      mimetype      TEXT,
      size          INTEGER,
      message       TEXT,
      status        TEXT NOT NULL DEFAULT 'new' CHECK (status IN ('new','reviewed','revision','resubmitted','accepted')),
      teacher_note  TEXT,
      grade         INTEGER,
      reviewed_at   TEXT,
      submitted_at  TEXT NOT NULL DEFAULT (datetime('now'))
    );

CREATE TABLE test_questions (
    test_id      INTEGER NOT NULL REFERENCES tests(id) ON DELETE CASCADE,
    question_id  INTEGER NOT NULL REFERENCES questions(id) ON DELETE CASCADE,
    order_index  INTEGER NOT NULL DEFAULT 0,
    PRIMARY KEY (test_id, question_id)
  );

CREATE TABLE test_sessions (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id      INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    subject_id   INTEGER REFERENCES subjects(id) ON DELETE SET NULL,
    mode         TEXT NOT NULL DEFAULT 'exam'
                 CHECK (mode IN ('exam', 'practice', 'topic', 'random')),
    total        INTEGER NOT NULL,
    score        INTEGER,
    status       TEXT NOT NULL DEFAULT 'in_progress'
                 CHECK (status IN ('in_progress', 'completed', 'abandoned')),
    started_at   TEXT NOT NULL DEFAULT (datetime('now')),
    finished_at  TEXT
  );

CREATE TABLE tests (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    title        TEXT NOT NULL,
    subject_slug TEXT NOT NULL,
    description  TEXT,
    created_by   INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    created_at   TEXT NOT NULL DEFAULT (datetime('now'))
  , show_answers INTEGER NOT NULL DEFAULT 1, time_limit INTEGER);

CREATE TABLE topics (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    subject_id  INTEGER NOT NULL REFERENCES subjects(id) ON DELETE CASCADE,
    name        TEXT NOT NULL,
    order_index INTEGER NOT NULL DEFAULT 0
  );

CREATE TABLE user_achievements (
    id             INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id        INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    achievement_id INTEGER NOT NULL REFERENCES achievements(id) ON DELETE CASCADE,
    unlocked_at    TEXT NOT NULL DEFAULT (datetime('now')),
    UNIQUE (user_id, achievement_id)
  );

CREATE TABLE user_answers (
    id               INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id       INTEGER NOT NULL REFERENCES test_sessions(id) ON DELETE CASCADE,
    question_id      INTEGER NOT NULL REFERENCES questions(id),
    chosen_option_id INTEGER REFERENCES options(id),
    is_correct       INTEGER,
    time_spent_sec   INTEGER,
    answered_at      TEXT NOT NULL DEFAULT (datetime('now')), answer_text TEXT,
    UNIQUE (session_id, question_id)
  );

CREATE TABLE user_permissions (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id    INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    permission TEXT NOT NULL,
    enabled    INTEGER NOT NULL DEFAULT 0,
    UNIQUE (user_id, permission)
  );

CREATE TABLE user_preferences (
    user_id    INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
    data       TEXT    NOT NULL DEFAULT '{}',
    updated_at TEXT    NOT NULL DEFAULT (datetime('now'))
  );

CREATE TABLE user_purchases (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id     INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    item_id     INTEGER NOT NULL REFERENCES shop_items(id) ON DELETE CASCADE,
    purchased_at TEXT NOT NULL DEFAULT (datetime('now')),
    UNIQUE(user_id, item_id)
  );

CREATE TABLE "users" (
        id              INTEGER PRIMARY KEY AUTOINCREMENT,
        email           TEXT UNIQUE NOT NULL,
        password_hash   TEXT NOT NULL,
        name            TEXT NOT NULL,
        role            TEXT NOT NULL DEFAULT 'student'
                        CHECK (role IN ('student','teacher','admin','free_student')),
        created_at      TEXT NOT NULL DEFAULT (datetime('now')),
        last_login      TEXT,
        xp              INTEGER NOT NULL DEFAULT 0,
        level           INTEGER NOT NULL DEFAULT 1,
        streak_current  INTEGER NOT NULL DEFAULT 0,
        streak_best     INTEGER NOT NULL DEFAULT 0,
        streak_date     TEXT,
        goal_tier       TEXT DEFAULT 'medium',
        avatar_frame    TEXT DEFAULT 'default',
        coins           INTEGER NOT NULL DEFAULT 0,
        active_title    TEXT DEFAULT NULL,
        active_theme    TEXT DEFAULT NULL,
        active_effect   TEXT DEFAULT NULL,
        token_version   INTEGER NOT NULL DEFAULT 0,
        lab_experiments INTEGER NOT NULL DEFAULT 0,
        lab_reactions   INTEGER NOT NULL DEFAULT 0,
        is_banned       INTEGER NOT NULL DEFAULT 0
      , pet_name TEXT, pet_color TEXT DEFAULT 'purple', pet_last_petted TEXT, pet_petting_streak INT DEFAULT 0, pet_last_star TEXT, pet_bg TEXT DEFAULT 'default', pet_bg_owned TEXT DEFAULT '[]', pet_last_fed TEXT, avatar_url TEXT DEFAULT NULL);

CREATE TABLE xp_log (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id    INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    amount     INTEGER NOT NULL,
    reason     TEXT NOT NULL,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  );

CREATE INDEX idx_announcements_class ON announcements(class_id);

CREATE INDEX idx_answers_session   ON user_answers(session_id);

CREATE INDEX idx_answers_sq           ON user_answers(session_id, question_id);

CREATE INDEX idx_assign_sess_assign ON assignment_sessions(assignment_id);

CREATE INDEX idx_assign_sess_user   ON assignment_sessions(user_id);

CREATE INDEX idx_assignments_class ON assignments(class_id);

CREATE INDEX idx_assignments_deadline      ON assignments(deadline);

CREATE INDEX idx_assignments_user  ON assignments(user_id);

CREATE INDEX idx_audit_log_admin ON admin_audit_log(admin_id);

CREATE INDEX idx_audit_log_date ON admin_audit_log(created_at DESC);

CREATE INDEX idx_avatar_req_status ON avatar_requests(status);

CREATE INDEX idx_avatar_req_user   ON avatar_requests(user_id);

CREATE INDEX idx_bio_mol_cat     ON bio_molecules(category);

CREATE INDEX idx_bio_mol_formula ON bio_molecules(formula);

CREATE INDEX idx_bio_user_chal   ON bio_user_challenges(user_id);

CREATE INDEX idx_bio_user_mol    ON bio_user_molecules(user_id);

CREATE INDEX idx_blocks_lesson ON lesson_blocks(lesson_id);

CREATE INDEX idx_bookmarks_user ON bookmarks(user_id);

CREATE INDEX idx_cc_class  ON class_courses(class_id);

CREATE INDEX idx_cc_course ON class_courses(course_id);

CREATE INDEX idx_challenges_user_week ON challenges(user_id, week);

CREATE INDEX idx_class_members_class ON class_members(class_id);

CREATE INDEX idx_class_members_user  ON class_members(user_id);

CREATE INDEX idx_courses_creator ON courses(created_by);

CREATE INDEX idx_courses_subject ON courses(subject_slug);

CREATE INDEX idx_cr_chat ON classroom_chat(session_id);

CREATE INDEX idx_cr_reactions ON classroom_chat_reactions(chat_id);

CREATE INDEX idx_cr_sessions_class ON classroom_sessions(class_id, status);

CREATE INDEX idx_cr_strokes ON classroom_strokes(session_id, page_num, seq);

CREATE INDEX idx_ctpl_creator ON course_templates(created_by);

CREATE INDEX idx_ctpl_public  ON course_templates(is_public);

CREATE INDEX idx_daily_goals_user ON daily_goals(user_id, date);

CREATE INDEX idx_error_log_date ON error_log(created_at DESC);

CREATE INDEX idx_file_access_file ON file_access(file_id);

CREATE INDEX idx_files_subject  ON files(subject_slug);

CREATE INDEX idx_files_uploader ON files(uploaded_by);

CREATE INDEX idx_folder_access_folder ON folder_access(folder_id);

CREATE INDEX idx_geo_subs_student ON geometry_submissions(student_id);

CREATE INDEX idx_geo_subs_task ON geometry_submissions(task_id);

CREATE INDEX idx_geo_tasks_teacher ON geometry_tasks(teacher_id);

CREATE INDEX idx_lcomments_lesson ON lesson_comments(lesson_id);

CREATE INDEX idx_lcomments_parent ON lesson_comments(parent_id);

CREATE INDEX idx_lcomments_user   ON lesson_comments(user_id);

CREATE INDEX idx_lessons_course ON lessons(course_id);

CREATE INDEX idx_live_answers_question ON live_answers(live_session_id, question_id);

CREATE INDEX idx_live_answers_session ON live_answers(live_session_id);

CREATE INDEX idx_live_sessions_class  ON live_sessions(class_id, status);

CREATE INDEX idx_lprogress_lesson ON lesson_progress(lesson_id);

CREATE INDEX idx_lprogress_user   ON lesson_progress(user_id);

CREATE INDEX idx_ltpl_creator ON lesson_templates(created_by);

CREATE INDEX idx_ltpl_public  ON lesson_templates(is_public);

CREATE INDEX idx_notes_lesson ON lesson_notes(lesson_id);

CREATE INDEX idx_notes_user   ON lesson_notes(user_id);

CREATE INDEX idx_notifications_user ON notifications(user_id, is_read);

CREATE INDEX idx_parent_links_student ON parent_links(student_id);

CREATE INDEX idx_parent_links_token   ON parent_links(token);

CREATE INDEX idx_parent_notif_link ON parent_notifications(parent_link_id, is_read);

CREATE INDEX idx_parent_notif_link_date ON parent_notifications(parent_link_id, created_at DESC);

CREATE INDEX idx_purchases_user ON user_purchases(user_id);

CREATE INDEX idx_questions_source ON questions(source_type);

CREATE INDEX idx_questions_subject ON questions(subject_id);

CREATE INDEX idx_questions_topic   ON questions(topic_id);

CREATE INDEX idx_rb_collection_user  ON rb_user_collection(user_id);

CREATE INDEX idx_rb_popdata_species  ON rb_population_data(species_id);

CREATE INDEX idx_rb_sightings_user   ON rb_sightings(user_id);

CREATE INDEX idx_rb_species_category ON rb_species(category);

CREATE INDEX idx_rb_species_group    ON rb_species(group_id);

CREATE INDEX idx_sections_course ON course_sections(course_id);

CREATE INDEX idx_sessions_user     ON test_sessions(user_id);

CREATE INDEX idx_sessions_user_status ON test_sessions(user_id, status);

CREATE INDEX idx_sessions_user_status_date ON test_sessions(user_id, status, started_at DESC);

CREATE INDEX idx_sq_session           ON session_questions(session_id);

CREATE INDEX idx_submissions_assignment ON submissions(assignment_id);

CREATE INDEX idx_submissions_class      ON submissions(class_id);

CREATE INDEX idx_submissions_student    ON submissions(student_id);

CREATE INDEX idx_test_sessions_status     ON test_sessions(status);

CREATE INDEX idx_test_sessions_user_status ON test_sessions(user_id, status);

CREATE UNIQUE INDEX idx_topics_uniq ON topics(subject_id, name);

CREATE INDEX idx_tpl_creator ON assignment_templates(created_by);

CREATE INDEX idx_user_achievements_user ON user_achievements(user_id);

CREATE INDEX idx_user_permissions_user ON user_permissions(user_id);

CREATE INDEX idx_xp_log_date ON xp_log(created_at);

CREATE INDEX idx_xp_log_user ON xp_log(user_id);

CREATE INDEX idx_xp_log_user_created       ON xp_log(user_id, created_at);
