-- Training stream events table & policies for Supabase realtime integration
-- Generated by GitHub Copilot to support the体育课训练 dashboard mock-to-cloud transition.

CREATE TABLE IF NOT EXISTS public.training_stream_events (
    id uuid PRIMARY KEY DEFAULT gen_random_uuid(), -- 记录ID
    training_id uuid NOT NULL, -- 训练会话ID，未来可关联 training_sessions
    event_type VARCHAR(32) NOT NULL, -- 事件类型：ack / telemetry / state / summary 等
    class_id uuid NOT NULL REFERENCES public.ak_classes(id) ON DELETE CASCADE, -- 班级ID
    student_id uuid REFERENCES public.ak_users(id) ON DELETE CASCADE, -- 学生ID，可为空表示班级级别事件
    device_id uuid REFERENCES public.ak_devices(id) ON DELETE SET NULL, -- 设备ID
    status VARCHAR(64), -- 状态描述，如 online/offline/ack_failed
    ack BOOLEAN, -- 是否为应答成功
    metrics JSONB, -- 指标明细：hr/spo2/temp 等
    payload JSONB, -- 额外原始载荷
    ingest_source VARCHAR(32) DEFAULT 'gateway', -- 来源：gateway/mock/simulator 等
    ingest_note TEXT, -- 额外说明，如模拟批次
    recorded_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), -- 事件发生时间
    ingested_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), -- 写入时间
    CONSTRAINT training_stream_events_target_chk CHECK (
        class_id IS NOT NULL
    )
);

COMMENT ON TABLE public.training_stream_events IS '课堂训练实时事件流，供 Supabase realtime 推送给教师端';
COMMENT ON COLUMN public.training_stream_events.training_id IS '训练会话ID（同一课堂 session 内共享）';
COMMENT ON COLUMN public.training_stream_events.event_type IS '事件类型：ack/telemetry/state/summary 等';
COMMENT ON COLUMN public.training_stream_events.class_id IS '班级ID，限定可见范围';
COMMENT ON COLUMN public.training_stream_events.student_id IS '学生ID；为空表示班级级别事件';
COMMENT ON COLUMN public.training_stream_events.device_id IS '关联设备；为空表示未绑定或无关设备事件';
COMMENT ON COLUMN public.training_stream_events.metrics IS '结构化指标（JSON），用于实时展示';
COMMENT ON COLUMN public.training_stream_events.payload IS '原始负载（JSON），用于调试或回放';
COMMENT ON COLUMN public.training_stream_events.ingest_source IS '事件来源：gateway/mock/simulator/service 等';
COMMENT ON COLUMN public.training_stream_events.ingest_note IS '模拟批次、异常说明等';

CREATE INDEX IF NOT EXISTS idx_training_stream_events_training_recorded
    ON public.training_stream_events (training_id, recorded_at DESC);

CREATE INDEX IF NOT EXISTS idx_training_stream_events_class_recorded
    ON public.training_stream_events (class_id, recorded_at DESC);

CREATE INDEX IF NOT EXISTS idx_training_stream_events_student_recorded
    ON public.training_stream_events (student_id, recorded_at DESC);

CREATE INDEX IF NOT EXISTS idx_training_stream_events_event_type
    ON public.training_stream_events (event_type);

CREATE INDEX IF NOT EXISTS idx_training_stream_events_device_recorded
    ON public.training_stream_events (device_id, recorded_at DESC);

ALTER TABLE public.training_stream_events ENABLE ROW LEVEL SECURITY;

-- 服务端（service_role）拥有完全访问权限，用于 Edge Function / Gateway 写入
CREATE POLICY "service role full access" ON public.training_stream_events
  FOR ALL
  USING (auth.role() = 'service_role')
  WITH CHECK (auth.role() = 'service_role');

-- 教师可以读取自己负责班级的训练事件
CREATE POLICY "teacher read class training events" ON public.training_stream_events
  FOR SELECT
  TO authenticated
  USING (
    auth.role() = 'service_role' OR
    public.current_user_has_permission('admin.system.manage') OR
    public.current_user_has_permission('school_admin.class.manage') OR
    EXISTS (
      SELECT 1
      FROM public.ak_users u
      JOIN public.ak_teacher_roles tr ON tr.user_id = u.id
      WHERE u.auth_id = auth.uid()
        AND tr.class_id = public.training_stream_events.class_id
    )
  );

-- 学生可查看自己的训练事件
CREATE POLICY "student read own training events" ON public.training_stream_events
  FOR SELECT
  TO authenticated
  USING (
    public.current_user_has_permission('student.training.read') AND
    EXISTS (
      SELECT 1
      FROM public.ak_users u
      WHERE u.auth_id = auth.uid()
        AND u.id = public.training_stream_events.student_id
    )
  );
DROP POLICY "teacher insert training events" ON public.training_stream_events;

-- 仅允许服务端或具备班级权限的教师写入事件（方便课堂模拟工具）
CREATE POLICY "teacher insert training events" ON public.training_stream_events
  FOR INSERT
  TO authenticated
  WITH CHECK (
    auth.role() = 'service_role' OR
    EXISTS (
      SELECT 1
      FROM public.ak_users u
      JOIN public.ak_teacher_roles tr ON tr.user_id = u.id
      WHERE u.auth_id = auth.uid()
        AND tr.class_id = public.training_stream_events.class_id
    )
  );

-- 清理时只允许服务角色删除
CREATE POLICY "service role delete training events" ON public.training_stream_events
  FOR DELETE
  USING (auth.role() = 'service_role');

-- 将表加入 Supabase realtime publication，避免重复添加导致错误
DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM pg_catalog.pg_publication_tables
    WHERE pubname = 'supabase_realtime'
      AND schemaname = 'public'
      AND tablename = 'training_stream_events'
  ) THEN
    EXECUTE 'ALTER PUBLICATION supabase_realtime ADD TABLE public.training_stream_events';
  END IF;
END;
$$;

-- 便于查询学生最近一次指标的视图
CREATE OR REPLACE VIEW public.training_stream_latest_metrics AS
SELECT DISTINCT ON (training_id, student_id)
    id,
    training_id,
    class_id,
    student_id,
    device_id,
    event_type,
    status,
    metrics,
    payload,
    recorded_at,
    ingested_at
FROM public.training_stream_events
WHERE event_type IN ('telemetry', 'metrics')
ORDER BY training_id, student_id, recorded_at DESC, ingested_at DESC, id DESC;

COMMENT ON VIEW public.training_stream_latest_metrics IS '每个学生在当前训练中的最近一次 telemetry/metrics 事件';
