-- Idempotent schema for CTMS (derived from current SQLAlchemy models)

DO $$
BEGIN
    CREATE TYPE public.user_role AS ENUM ('ADMIN', 'PM', 'CRA', 'PV', 'IMP', 'QA');
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

DO $$
BEGIN
    ALTER TYPE public.user_role ADD VALUE IF NOT EXISTS 'QA';
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

DO $$
BEGIN
    CREATE TYPE public.user_status AS ENUM ('PENDING', 'ACTIVE', 'REJECTED', 'DISABLED');
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

CREATE TABLE IF NOT EXISTS public.users (
    id uuid PRIMARY KEY,
    email character varying(255) NOT NULL,
    password_hash character varying(255) NOT NULL,
    full_name character varying(255) NOT NULL,
    role public.user_role NOT NULL,
    department character varying(255) NOT NULL,
    status public.user_status NOT NULL DEFAULT 'PENDING',
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    approved_by uuid,
    approved_at timestamp with time zone,
    avatar_url character varying(500),
    CONSTRAINT uq_users_email UNIQUE (email)
);

CREATE TABLE IF NOT EXISTS public.studies (
    id uuid PRIMARY KEY,
    code character varying(50) NOT NULL,
    name character varying(200) NOT NULL,
    sponsor character varying(200),
    protocol_no character varying(100),
    phase character varying(50),
    status character varying(20) NOT NULL DEFAULT 'DRAFT',
    visit_interval_days integer,
    visit_total integer,
    visit_window_start_offset integer,
    visit_window_end_offset integer,
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT uq_studies_code UNIQUE (code),
    CONSTRAINT fk_studies_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.sites (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    name character varying(200) NOT NULL,
    city character varying(100),
    pi_name character varying(100),
    contact character varying(100),
    is_active boolean NOT NULL DEFAULT true,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_sites_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.study_members (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    user_id uuid NOT NULL,
    role_in_study character varying(20) NOT NULL,
    is_active boolean NOT NULL DEFAULT true,
    added_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT uq_study_member UNIQUE (study_id, user_id),
    CONSTRAINT fk_study_members_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_study_members_user_id FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.milestones (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    type character varying(50) NOT NULL,
    name character varying(200) NOT NULL,
    planned_date date,
    actual_date date,
    status character varying(20) NOT NULL DEFAULT 'NOT_STARTED',
    site_id uuid,
    owner_id uuid,
    notes text,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_milestones_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_milestones_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
    CONSTRAINT fk_milestones_owner_id FOREIGN KEY (owner_id) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.subjects (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    site_id uuid NOT NULL,
    subject_no character varying(50) NOT NULL,
    status character varying(20) NOT NULL DEFAULT 'SCREENING',
    screening_date date,
    consent_date date,
    enrollment_date date,
    completion_date date,
    drop_reason text,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT uq_subject_study_no UNIQUE (study_id, subject_no),
    CONSTRAINT fk_subjects_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_subjects_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.subject_histories (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    subject_id uuid NOT NULL,
    record_date date,
    content text NOT NULL,
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_subject_histories_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_subject_histories_subject_id FOREIGN KEY (subject_id) REFERENCES public.subjects(id) ON DELETE RESTRICT,
    CONSTRAINT fk_subject_histories_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.visits (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    subject_id uuid NOT NULL,
    visit_code character varying(50) NOT NULL,
    planned_date date,
    actual_date date,
    status character varying(20) NOT NULL DEFAULT 'PLANNED',
    window_start date,
    window_end date,
    notes text,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_visits_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_visits_subject_id FOREIGN KEY (subject_id) REFERENCES public.subjects(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.adverse_events (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    site_id uuid,
    subject_id uuid,
    visit_id uuid,
    term character varying(255) NOT NULL,
    onset_date date,
    resolution_date date,
    seriousness character varying(50) NOT NULL,
    severity character varying(50) NOT NULL,
    causality character varying(50),
    action_taken text,
    outcome character varying(50),
    reported_to_sponsor boolean NOT NULL DEFAULT false,
    report_due_date date,
    status character varying(20) NOT NULL DEFAULT 'NEW',
    description text,
    created_by uuid NOT NULL,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_adverse_events_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_adverse_events_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
    CONSTRAINT fk_adverse_events_subject_id FOREIGN KEY (subject_id) REFERENCES public.subjects(id) ON DELETE RESTRICT,
    CONSTRAINT fk_adverse_events_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.finance_contracts (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    site_name character varying(255) NOT NULL,
    contract_no character varying(100) NOT NULL,
    signed_date date,
    amount numeric(12, 2) NOT NULL,
    currency character varying(10) NOT NULL DEFAULT 'CNY',
    remark text,
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_finance_contracts_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_finance_contracts_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.finance_specials (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    site_name character varying(255) NOT NULL,
    fee_type character varying(50) NOT NULL,
    amount numeric(12, 2) NOT NULL,
    occur_date date,
    staff_name character varying(100),
    remark text,
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_finance_specials_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_finance_specials_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.contract_fees (
    id uuid PRIMARY KEY,
    project_id uuid NOT NULL,
    center_id uuid NOT NULL,
    contract_amount numeric(12, 2) NOT NULL,
    contract_cases integer NOT NULL,
    actual_cases integer,
    settlement_amount numeric(12, 2),
    final_payment_amount numeric(12, 2),
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT uq_contract_fees_project_center UNIQUE (project_id, center_id),
    CONSTRAINT fk_contract_fees_project_id FOREIGN KEY (project_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_contract_fees_center_id FOREIGN KEY (center_id) REFERENCES public.sites(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.contract_fee_payments (
    id uuid PRIMARY KEY,
    contract_fee_id uuid NOT NULL,
    seq integer NOT NULL,
    amount numeric(12, 2) NOT NULL,
    paid_date date,
    verified_date date,
    is_paid boolean NOT NULL DEFAULT false,
    is_verified boolean NOT NULL DEFAULT false,
    remark text,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_contract_fee_payments_contract_fee_id FOREIGN KEY (contract_fee_id) REFERENCES public.contract_fees(id) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS public.special_expenses (
    id uuid PRIMARY KEY,
    project_id uuid NOT NULL,
    center_id uuid,
    category character varying(50) NOT NULL,
    amount numeric(12, 2) NOT NULL,
    happen_date date,
    description text,
    is_paid boolean NOT NULL DEFAULT false,
    paid_date date,
    is_verified boolean NOT NULL DEFAULT false,
    verified_date date,
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_special_expenses_project_id FOREIGN KEY (project_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_special_expenses_center_id FOREIGN KEY (center_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
    CONSTRAINT fk_special_expenses_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.fee_attachments (
    id uuid PRIMARY KEY,
    entity_type character varying(50) NOT NULL,
    entity_id uuid NOT NULL,
    file_type character varying(30) NOT NULL,
    filename character varying(255) NOT NULL,
    mime_type character varying(100),
    size integer NOT NULL,
    storage_key character varying(500),
    url text,
    uploaded_by uuid NOT NULL,
    uploaded_at timestamp with time zone NOT NULL DEFAULT now(),
    is_deleted boolean NOT NULL DEFAULT false,
    CONSTRAINT fk_fee_attachments_uploaded_by FOREIGN KEY (uploaded_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.finance_items (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    site_id uuid,
    subject_id uuid,
    visit_id uuid,
    category character varying(50) NOT NULL,
    title character varying(255) NOT NULL,
    description text,
    currency character varying(10) NOT NULL DEFAULT 'CNY',
    amount numeric(12, 2) NOT NULL,
    occur_date date NOT NULL,
    status character varying(20) NOT NULL DEFAULT 'DRAFT',
    submitted_at timestamp with time zone,
    approved_at timestamp with time zone,
    rejected_at timestamp with time zone,
    paid_at timestamp with time zone,
    approver_id uuid,
    payer_id uuid,
    reject_reason text,
    created_by uuid NOT NULL,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_finance_items_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_finance_items_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
    CONSTRAINT fk_finance_items_subject_id FOREIGN KEY (subject_id) REFERENCES public.subjects(id) ON DELETE RESTRICT,
    CONSTRAINT fk_finance_items_approver_id FOREIGN KEY (approver_id) REFERENCES public.users(id) ON DELETE RESTRICT,
    CONSTRAINT fk_finance_items_payer_id FOREIGN KEY (payer_id) REFERENCES public.users(id) ON DELETE RESTRICT,
    CONSTRAINT fk_finance_items_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.drug_shipments (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    direction character varying(20) NOT NULL,
    center_id uuid,
    site_name character varying(255) NOT NULL,
    ship_date date,
    receive_date date,
    quantity integer,
    batch_no character varying(100),
    carrier character varying(100),
    tracking_no character varying(100),
    status character varying(30) NOT NULL,
    remark text,
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_drug_shipments_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_drug_shipments_center_id FOREIGN KEY (center_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
    CONSTRAINT fk_drug_shipments_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.startup_feasibility (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    site_id uuid,
    submit_date date,
    accept_date date,
    approved_date date,
    project_no character varying(100),
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_startup_feasibility_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_startup_feasibility_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
    CONSTRAINT fk_startup_feasibility_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.startup_ethics (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    site_id uuid,
    submit_date date,
    accept_date date,
    meeting_date date,
    approved_date date,
    approval_no character varying(100),
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_startup_ethics_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_startup_ethics_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
    CONSTRAINT fk_startup_ethics_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.kickoff_meetings (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    site_id uuid,
    kickoff_date date,
    attendees json,
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_kickoff_meetings_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_kickoff_meetings_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
    CONSTRAINT fk_kickoff_meetings_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.training_authorizations (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    name character varying(100) NOT NULL,
    role character varying(100),
    site_name character varying(255),
    trained boolean NOT NULL DEFAULT false,
    authorized boolean NOT NULL DEFAULT false,
    trained_date date,
    authorized_date date,
    remark text,
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_training_authorizations_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_training_authorizations_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.knowledge_notes (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    site_name character varying(255) NOT NULL,
    title character varying(255) NOT NULL,
    content text NOT NULL,
    level character varying(50),
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_knowledge_notes_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_knowledge_notes_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.faq_categories (
    id uuid PRIMARY KEY,
    study_id uuid,
    name character varying(100) NOT NULL,
    description text,
    sort_order integer NOT NULL DEFAULT 0,
    is_active boolean NOT NULL DEFAULT true,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT uq_faq_category_name UNIQUE (study_id, name),
    CONSTRAINT fk_faq_categories_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.faq_items (
    id uuid PRIMARY KEY,
    study_id uuid,
    category_id uuid NOT NULL,
    best_reply_id uuid,
    status character varying(20) NOT NULL DEFAULT 'PENDING',
    resolved_by_confirm boolean NOT NULL DEFAULT false,
    question text NOT NULL,
    answer text NOT NULL,
    keywords character varying(255),
    version integer NOT NULL DEFAULT 1,
    is_active boolean NOT NULL DEFAULT true,
    created_by uuid NOT NULL,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_faq_items_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_faq_items_category_id FOREIGN KEY (category_id) REFERENCES public.faq_categories(id) ON DELETE RESTRICT,
    CONSTRAINT fk_faq_items_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.faq_replies (
    id uuid PRIMARY KEY,
    faq_id uuid NOT NULL,
    study_id uuid,
    content text NOT NULL,
    created_by uuid NOT NULL,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    quote_reply_id uuid,
    is_deleted boolean NOT NULL DEFAULT false,
    CONSTRAINT fk_faq_replies_faq_id FOREIGN KEY (faq_id) REFERENCES public.faq_items(id) ON DELETE RESTRICT,
    CONSTRAINT fk_faq_replies_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_faq_replies_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT,
    CONSTRAINT fk_faq_replies_quote_reply_id FOREIGN KEY (quote_reply_id) REFERENCES public.faq_replies(id) ON DELETE RESTRICT
);

DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM pg_constraint WHERE conname = 'fk_faq_items_best_reply_id'
    ) THEN
        ALTER TABLE public.faq_items
            ADD CONSTRAINT fk_faq_items_best_reply_id
            FOREIGN KEY (best_reply_id) REFERENCES public.faq_replies(id) ON DELETE SET NULL;
    END IF;
END $$;

CREATE TABLE IF NOT EXISTS public.attachments (
    id uuid PRIMARY KEY,
    study_id uuid NOT NULL,
    entity_type character varying(50) NOT NULL,
    entity_id uuid NOT NULL,
    filename character varying(255) NOT NULL,
    file_path character varying(500) NOT NULL,
    file_size integer NOT NULL,
    content_type character varying(100),
    uploaded_by uuid NOT NULL,
    uploaded_at timestamp with time zone NOT NULL DEFAULT now(),
    is_deleted boolean NOT NULL DEFAULT false,
    CONSTRAINT fk_attachments_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_attachments_uploaded_by FOREIGN KEY (uploaded_by) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE TABLE IF NOT EXISTS public.audit_logs (
    id uuid PRIMARY KEY,
    study_id uuid,
    entity_type character varying(50) NOT NULL,
    entity_id uuid,
    action character varying(50) NOT NULL,
    detail text,
    operator_id uuid NOT NULL,
    operator_role character varying(50) NOT NULL,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_audit_logs_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_audit_logs_operator_id FOREIGN KEY (operator_id) REFERENCES public.users(id) ON DELETE RESTRICT
);

CREATE INDEX IF NOT EXISTS ix_sites_study_id ON public.sites (study_id);
CREATE INDEX IF NOT EXISTS ix_study_members_study_id ON public.study_members (study_id);
CREATE INDEX IF NOT EXISTS ix_milestones_study_id ON public.milestones (study_id);
CREATE INDEX IF NOT EXISTS ix_subjects_study_id ON public.subjects (study_id);
CREATE INDEX IF NOT EXISTS ix_subjects_site_id ON public.subjects (site_id);
CREATE INDEX IF NOT EXISTS ix_subject_histories_study_id ON public.subject_histories (study_id);
CREATE INDEX IF NOT EXISTS ix_subject_histories_subject_id ON public.subject_histories (subject_id);
CREATE INDEX IF NOT EXISTS ix_visits_subject_id ON public.visits (subject_id);
CREATE INDEX IF NOT EXISTS ix_adverse_events_study_id ON public.adverse_events (study_id);
CREATE INDEX IF NOT EXISTS ix_adverse_events_site_id ON public.adverse_events (site_id);
CREATE INDEX IF NOT EXISTS ix_adverse_events_subject_id ON public.adverse_events (subject_id);
CREATE INDEX IF NOT EXISTS ix_finance_contracts_study_id ON public.finance_contracts (study_id);
CREATE INDEX IF NOT EXISTS ix_finance_specials_study_id ON public.finance_specials (study_id);
CREATE INDEX IF NOT EXISTS ix_finance_items_study_id ON public.finance_items (study_id);
CREATE INDEX IF NOT EXISTS ix_finance_items_site_id ON public.finance_items (site_id);
CREATE INDEX IF NOT EXISTS ix_finance_items_subject_id ON public.finance_items (subject_id);
CREATE INDEX IF NOT EXISTS ix_drug_shipments_study_id ON public.drug_shipments (study_id);
CREATE INDEX IF NOT EXISTS ix_drug_shipments_center_id ON public.drug_shipments (center_id);
CREATE INDEX IF NOT EXISTS ix_startup_feasibility_study_id ON public.startup_feasibility (study_id);
CREATE INDEX IF NOT EXISTS ix_startup_ethics_study_id ON public.startup_ethics (study_id);
CREATE INDEX IF NOT EXISTS ix_kickoff_meetings_study_id ON public.kickoff_meetings (study_id);
CREATE INDEX IF NOT EXISTS ix_training_authorizations_study_id ON public.training_authorizations (study_id);
CREATE INDEX IF NOT EXISTS ix_knowledge_notes_study_id ON public.knowledge_notes (study_id);
CREATE INDEX IF NOT EXISTS ix_faq_categories_study_id ON public.faq_categories (study_id);
CREATE INDEX IF NOT EXISTS ix_faq_items_study_id ON public.faq_items (study_id);
CREATE INDEX IF NOT EXISTS ix_faq_items_category_id ON public.faq_items (category_id);
CREATE INDEX IF NOT EXISTS ix_faq_replies_faq_id ON public.faq_replies (faq_id);
CREATE INDEX IF NOT EXISTS ix_faq_replies_study_id ON public.faq_replies (study_id);

-- =========================================
-- DEMO SEED DATA (idempotent)
-- =========================================
INSERT INTO public.users (
    id, email, password_hash, full_name, role, department, status, created_at, updated_at
) VALUES
    ('11111111-1111-1111-1111-111111111111', 'admin@example.com', '$2y$12$FMfyBt7YfZWeh/x8WMEIA.S6VUTIMryk2NxWHyOOuJvd6YrDwHAdu', 'System Admin', 'ADMIN', 'SYSTEM', 'ACTIVE', '2025-01-05 08:00:00+00', '2025-01-05 08:00:00+00'),
    ('22222222-2222-2222-2222-222222222222', 'pm@example.com', '$2y$12$P9UDKu48ru84uVrlquqhXufmw/CfMEzQosC0X8eT2EmY/PgM/03j2', '项目经理', 'PM', 'PMO', 'ACTIVE', '2025-01-05 08:10:00+00', '2025-01-05 08:10:00+00'),
    ('33333333-3333-3333-3333-333333333333', 'cra@example.com', '$2y$12$D/.ZeDrUByPZFPnAl9MnKuzKn2G4ctKQ9IAS/CqS2sfMdE/5NaKAK', 'CRA 用户', 'CRA', 'CRA', 'ACTIVE', '2025-01-05 08:20:00+00', '2025-01-05 08:20:00+00'),
    ('44444444-4444-4444-4444-444444444444', 'qa@example.com', '$2y$12$P9UDKu48ru84uVrlquqhXufmw/CfMEzQosC0X8eT2EmY/PgM/03j2', 'QA 用户', 'QA', 'QA', 'ACTIVE', '2025-01-05 08:30:00+00', '2025-01-05 08:30:00+00'),
    ('55555555-5555-5555-5555-555555555555', 'pv@example.com', '$2y$12$P9UDKu48ru84uVrlquqhXufmw/CfMEzQosC0X8eT2EmY/PgM/03j2', 'PV 用户', 'PV', 'PV', 'ACTIVE', '2025-01-05 08:40:00+00', '2025-01-05 08:40:00+00'),
    ('66666666-6666-6666-6666-666666666666', 'imp@example.com', '$2y$12$P9UDKu48ru84uVrlquqhXufmw/CfMEzQosC0X8eT2EmY/PgM/03j2', '药品管理员', 'IMP', 'IMP', 'ACTIVE', '2025-01-05 08:50:00+00', '2025-01-05 08:50:00+00')
ON CONFLICT (email) DO UPDATE SET
    password_hash = EXCLUDED.password_hash,
    full_name = EXCLUDED.full_name,
    role = EXCLUDED.role,
    department = EXCLUDED.department,
    status = EXCLUDED.status,
    updated_at = EXCLUDED.updated_at;

INSERT INTO public.studies (
    id, code, name, sponsor, protocol_no, phase, status, visit_interval_days, visit_total, visit_window_start_offset, visit_window_end_offset, created_by, created_at
) VALUES (
    'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
    'DEMO-CTMS',
    '示例项目：糖尿病新药',
    'Demo Pharma',
    'DP-001',
    'Phase II',
    'ACTIVE',
    7,
    3,
    -2,
    2,
    (SELECT id FROM public.users WHERE email = 'admin@example.com'),
    '2025-01-06 08:00:00+00'
) ON CONFLICT (code) DO UPDATE SET
    name = EXCLUDED.name,
    sponsor = EXCLUDED.sponsor,
    protocol_no = EXCLUDED.protocol_no,
    phase = EXCLUDED.phase,
    status = EXCLUDED.status,
    visit_interval_days = EXCLUDED.visit_interval_days,
    visit_total = EXCLUDED.visit_total,
    visit_window_start_offset = EXCLUDED.visit_window_start_offset,
    visit_window_end_offset = EXCLUDED.visit_window_end_offset,
    created_by = EXCLUDED.created_by;

INSERT INTO public.sites (
    id, study_id, name, city, pi_name, contact, is_active, created_at
) VALUES
    ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', '北京', '李主任', '010-12345678', true, '2025-01-06 09:00:00+00'),
    ('cccccccc-cccc-cccc-cccc-cccccccccccc', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '上海瑞金医院', '上海', '王主任', '021-12345678', true, '2025-01-06 09:10:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.study_members (
    id, study_id, user_id, role_in_study, is_active, added_at
) VALUES
    ('dddddddd-dddd-dddd-dddd-dddddddddddd', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), (SELECT id FROM public.users WHERE email = 'admin@example.com'), 'ADMIN', true, '2025-01-06 10:00:00+00'),
    ('eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), (SELECT id FROM public.users WHERE email = 'pm@example.com'), 'PM', true, '2025-01-06 10:05:00+00'),
    ('ffffffff-ffff-ffff-ffff-ffffffffffff', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), (SELECT id FROM public.users WHERE email = 'cra@example.com'), 'CRA', true, '2025-01-06 10:10:00+00'),
    ('11111111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), (SELECT id FROM public.users WHERE email = 'qa@example.com'), 'QA', true, '2025-01-06 10:15:00+00'),
    ('22222222-3333-4444-5555-666666666666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), (SELECT id FROM public.users WHERE email = 'pv@example.com'), 'PV', true, '2025-01-06 10:20:00+00'),
    ('33333333-4444-5555-6666-777777777777', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), (SELECT id FROM public.users WHERE email = 'imp@example.com'), 'IMP', true, '2025-01-06 10:25:00+00')
ON CONFLICT (study_id, user_id) DO UPDATE SET
    role_in_study = EXCLUDED.role_in_study,
    is_active = EXCLUDED.is_active;

INSERT INTO public.milestones (
    id, study_id, type, name, planned_date, actual_date, status, site_id, owner_id, notes, created_at, updated_at
) VALUES
    ('10101010-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'SIV', '启动会', '2025-01-10', '2025-01-12', 'DONE', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '现场启动完成', '2025-01-06 12:00:00+00', '2025-01-12 10:00:00+00'),
    ('20202020-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'LPI', '首例入组', '2025-02-01', NULL, 'NOT_STARTED', 'cccccccc-cccc-cccc-cccc-cccccccccccc', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '待完成', '2025-01-06 12:10:00+00', '2025-01-06 12:10:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.finance_contracts (
    id, study_id, site_name, contract_no, signed_date, amount, currency, remark, created_by, created_at, updated_at
) VALUES
    ('77777777-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', 'CON-001', '2025-01-08', 1200000.00, 'CNY', '首批合同签署', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-08 09:00:00+00', '2025-01-08 09:00:00+00'),
    ('77777777-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '上海瑞金医院', 'CON-002', '2025-01-10', 980000.00, 'CNY', '分中心合同签署', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-10 09:00:00+00', '2025-01-10 09:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.finance_specials (
    id, study_id, site_name, fee_type, amount, occur_date, staff_name, remark, created_by, created_at, updated_at
) VALUES
    ('88888888-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', '差旅', 5200.00, '2025-01-15', '赵敏', 'SIV 差旅费', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-15 10:00:00+00', '2025-01-15 10:00:00+00'),
    ('88888888-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '上海瑞金医院', '住宿', 3200.00, '2025-01-18', '李雷', '监查住宿费', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-18 10:00:00+00', '2025-01-18 10:00:00+00'),
    ('88888888-aaaa-bbbb-cccc-333333333333', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', '交通', 860.00, '2025-01-20', '韩梅梅', '市内交通费', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-20 10:00:00+00', '2025-01-20 10:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.finance_items (
    id, study_id, site_id, subject_id, visit_id, category, title, description, currency, amount, occur_date, status, submitted_at, approved_at, rejected_at, paid_at, approver_id, payer_id, reject_reason, created_by, created_at, updated_at
) VALUES
    ('99999999-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', NULL, NULL, 'SITE_FEE', '启动费', '中心启动费用', 'CNY', 30000.00, '2025-01-12', 'PAID', '2025-01-13 08:00:00+00', '2025-01-13 10:00:00+00', NULL, '2025-01-15 09:00:00+00', (SELECT id FROM public.users WHERE email = 'pm@example.com'), (SELECT id FROM public.users WHERE email = 'admin@example.com'), NULL, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 09:00:00+00', '2025-01-15 09:00:00+00'),
    ('99999999-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'cccccccc-cccc-cccc-cccc-cccccccccccc', NULL, NULL, 'TRAVEL', '监查差旅', 'CRA 监查差旅报销', 'CNY', 4800.00, '2025-01-20', 'APPROVED', '2025-01-21 08:00:00+00', '2025-01-21 10:00:00+00', NULL, NULL, (SELECT id FROM public.users WHERE email = 'pm@example.com'), NULL, NULL, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-20 10:00:00+00', '2025-01-21 10:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.drug_shipments (
    id, study_id, direction, center_id, site_name, ship_date, receive_date, quantity, batch_no, carrier, tracking_no, status, remark, created_by, created_at, updated_at
) VALUES
    ('aaaa1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '寄送', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '北京协和医院', '2025-01-12', NULL, 200, 'DP-001', '顺丰', 'SF100001', '运输中', '首批寄送：DP-001 片剂 50mg × 200 盒', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-12 11:00:00+00', '2025-01-12 11:00:00+00'),
    ('bbbb1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '寄送', 'cccccccc-cccc-cccc-cccc-cccccccccccc', '上海瑞金医院', '2025-01-13', '2025-01-14', 150, 'DP-001', '京东物流', 'JD200002', '已签收', '分中心补货：DP-001 片剂 50mg × 150 盒', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-13 11:00:00+00', '2025-01-14 09:00:00+00'),
    ('cccc1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '回收', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '北京协和医院', '2025-02-05', '2025-02-06', NULL, 'DP-001', '顺丰', 'SF100003', '已回收', '首批回收：空药盒及剩余药品', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-02-05 14:00:00+00', '2025-02-06 09:00:00+00'),
    ('dddd1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '回收', 'cccccccc-cccc-cccc-cccc-cccccccccccc', '上海瑞金医院', '2025-02-08', NULL, NULL, 'DP-001', '德邦', 'DB300004', '运输中', '回收途中：冷链箱回收', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-02-08 16:00:00+00', '2025-02-08 16:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.startup_feasibility (
    id, study_id, site_id, submit_date, accept_date, approved_date, project_no, created_by, created_at, updated_at
) VALUES
    ('eeee1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '2025-01-02', '2025-01-05', '2025-01-10', 'FEA-BJ-001', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-10 10:00:00+00', '2025-01-10 10:00:00+00'),
    ('ffff1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'cccccccc-cccc-cccc-cccc-cccccccccccc', '2025-01-03', '2025-01-06', '2025-01-12', 'FEA-SH-002', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 10:00:00+00', '2025-01-12 10:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.startup_ethics (
    id, study_id, site_id, submit_date, accept_date, meeting_date, approved_date, approval_no, created_by, created_at, updated_at
) VALUES
    ('1111aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '2025-01-04', '2025-01-07', '2025-01-15', '2025-01-20', 'ETH-BJ-001', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-20 11:00:00+00', '2025-01-20 11:00:00+00'),
    ('2222aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'cccccccc-cccc-cccc-cccc-cccccccccccc', '2025-01-05', '2025-01-08', '2025-01-16', '2025-01-22', 'ETH-SH-002', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-22 11:00:00+00', '2025-01-22 11:00:00+00')
ON CONFLICT (id) DO NOTHING;

UPDATE public.startup_feasibility
SET site_id = (SELECT id FROM public.sites WHERE name ILIKE '%北京%' OR city ILIKE '%北京%' LIMIT 1)
WHERE site_id IS NULL AND project_no ILIKE '%-BJ-%';

UPDATE public.startup_feasibility
SET site_id = (SELECT id FROM public.sites WHERE name ILIKE '%上海%' OR city ILIKE '%上海%' LIMIT 1)
WHERE site_id IS NULL AND project_no ILIKE '%-SH-%';

UPDATE public.startup_ethics
SET site_id = (SELECT id FROM public.sites WHERE name ILIKE '%北京%' OR city ILIKE '%北京%' LIMIT 1)
WHERE site_id IS NULL AND approval_no ILIKE '%-BJ-%';

UPDATE public.startup_ethics
SET site_id = (SELECT id FROM public.sites WHERE name ILIKE '%上海%' OR city ILIKE '%上海%' LIMIT 1)
WHERE site_id IS NULL AND approval_no ILIKE '%-SH-%';

INSERT INTO public.kickoff_meetings (
    id, study_id, kickoff_date, attendees, created_by, created_at, updated_at
) VALUES (
    '3333aaaa-2222-3333-4444-555555555555',
    (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
    '2025-01-12',
    '["张三","李四","王五"]'::json,
    (SELECT id FROM public.users WHERE email = 'pm@example.com'),
    '2025-01-12 13:00:00+00',
    '2025-01-12 13:00:00+00'
) ON CONFLICT (id) DO NOTHING;

INSERT INTO public.training_authorizations (
    id, study_id, name, role, site_name, trained, authorized, trained_date, authorized_date, remark, created_by, created_at, updated_at
) VALUES
    ('4444bbbb-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '赵敏', '研究医生', '北京协和医院', true, false, '2025-01-12', NULL, '待授权', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 15:00:00+00', '2025-01-12 15:00:00+00'),
    ('5555bbbb-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '李雷', 'CRC', '上海瑞金医院', false, true, NULL, '2025-01-18', '先授权后补训', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-18 15:00:00+00', '2025-01-18 15:00:00+00'),
    ('6666bbbb-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '韩梅梅', '药房管理员', '北京协和医院', true, true, '2025-01-10', '2025-01-12', '已完成', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 16:00:00+00', '2025-01-12 16:00:00+00'),
    ('7777bbbb-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '王强', 'CRA', '上海瑞金医院', false, false, NULL, NULL, '待安排', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-20 16:00:00+00', '2025-01-20 16:00:00+00'),
    ('8888bbbb-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '刘晨', '研究护士', '北京协和医院', true, false, '2025-01-14', NULL, '仅完成培训', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-14 16:00:00+00', '2025-01-14 16:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.subjects (
    id, study_id, site_id, subject_no, status, screening_date, consent_date, enrollment_date, completion_date, drop_reason, created_at, updated_at
) VALUES
    ('11111111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'SUBJ-001', 'ENROLLED', '2025-01-05', '2025-01-06', '2025-01-10', NULL, NULL, '2025-01-10 10:00:00+00', '2025-01-10 10:00:00+00'),
    ('22222222-3333-4444-5555-666666666666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'cccccccc-cccc-cccc-cccc-cccccccccccc', 'SUBJ-002', 'SCREENING', '2025-01-12', '2025-01-13', NULL, NULL, NULL, '2025-01-12 10:00:00+00', '2025-01-12 10:00:00+00'),
    ('33333333-4444-5555-6666-777777777777', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'SUBJ-003', 'COMPLETED', '2024-12-20', '2024-12-21', '2024-12-28', '2025-02-05', NULL, '2025-02-05 10:00:00+00', '2025-02-05 10:00:00+00')
ON CONFLICT (study_id, subject_no) DO UPDATE SET
    site_id = EXCLUDED.site_id,
    status = EXCLUDED.status,
    screening_date = EXCLUDED.screening_date,
    consent_date = EXCLUDED.consent_date,
    enrollment_date = EXCLUDED.enrollment_date,
    completion_date = EXCLUDED.completion_date,
    drop_reason = EXCLUDED.drop_reason,
    updated_at = EXCLUDED.updated_at;

INSERT INTO public.subject_histories (
    id, study_id, subject_id, record_date, content, created_by, created_at, updated_at
) VALUES
    ('55555555-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '11111111-2222-3333-4444-555555555555', '2025-01-08', '既往有高血压病史，长期服药控制。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-08 11:00:00+00', '2025-01-08 11:00:00+00'),
    ('55555555-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '22222222-3333-4444-5555-666666666666', '2025-01-13', '糖耐量异常，需进一步评估。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-13 11:00:00+00', '2025-01-13 11:00:00+00'),
    ('55555555-aaaa-bbbb-cccc-333333333333', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '33333333-4444-5555-6666-777777777777', '2025-01-02', '既往病史稳定，未见严重合并症。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-02 11:00:00+00', '2025-01-02 11:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.visits (
    id, study_id, subject_id, visit_code, planned_date, actual_date, status, window_start, window_end, notes, created_at, updated_at
) VALUES
    ('44444444-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '11111111-2222-3333-4444-555555555555', 'V1', '2025-01-09', '2025-01-10', 'DONE', '2025-01-07', '2025-01-12', '按期完成', '2025-01-10 12:00:00+00', '2025-01-10 12:00:00+00'),
    ('44444444-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '11111111-2222-3333-4444-555555555555', 'FU1', '2025-02-09', NULL, 'PLANNED', '2025-02-07', '2025-02-12', NULL, '2025-01-20 12:00:00+00', '2025-01-20 12:00:00+00'),
    ('44444444-aaaa-bbbb-cccc-333333333333', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '11111111-2222-3333-4444-555555555555', 'FU2', '2025-03-11', NULL, 'PLANNED', '2025-03-09', '2025-03-14', NULL, '2025-02-01 12:00:00+00', '2025-02-01 12:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.adverse_events (
    id, study_id, site_id, subject_id, visit_id, term, onset_date, resolution_date, seriousness, severity, causality, action_taken, outcome, reported_to_sponsor, report_due_date, status, description, created_by, created_at, updated_at
) VALUES
    ('66666666-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '11111111-2222-3333-4444-555555555555', '44444444-aaaa-bbbb-cccc-111111111111', '轻微头痛', '2025-01-10', '2025-01-11', 'NON_SERIOUS', 'MILD', '可能相关', '休息观察', '恢复', true, '2025-01-20', 'CLOSED', '参与者轻微头痛，次日缓解。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-10 13:00:00+00', '2025-01-11 09:00:00+00'),
    ('66666666-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'cccccccc-cccc-cccc-cccc-cccccccccccc', '22222222-3333-4444-5555-666666666666', NULL, '血糖升高', '2025-01-18', NULL, 'SERIOUS', 'SEVERE', '相关', '调整用药', '未恢复', false, '2025-01-28', 'NEW', '筛选期血糖异常。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-18 13:00:00+00', '2025-01-18 13:00:00+00'),
    ('66666666-aaaa-bbbb-cccc-333333333333', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '11111111-2222-3333-4444-555555555555', NULL, '轻度皮疹', '2025-02-10', NULL, 'NON_SERIOUS', 'MODERATE', '待评估', NULL, '未恢复', false, '2025-02-20', 'FOLLOW_UP', '出现皮疹，持续观察。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-02-10 13:00:00+00', '2025-02-10 13:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.knowledge_notes (
    id, study_id, site_name, title, content, level, created_by, created_at, updated_at
) VALUES
    ('4444aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', '样本采集注意', '采血需在早晨空腹完成，样本 2 小时内送达。', '高', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 18:00:00+00', '2025-01-12 18:00:00+00'),
    ('5555aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '上海瑞金医院', '访视资料上传', '访视完成后 24 小时内完成资料上传与核对。', '中', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-15 18:00:00+00', '2025-01-15 18:00:00+00'),
    ('6666aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', '冷链运输提醒', '冷链记录必须随药品一起封存。', '低', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-18 18:00:00+00', '2025-01-18 18:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.faq_categories (
    id, study_id, name, description, sort_order, is_active, created_at, updated_at
) VALUES
    ('7777aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '访视相关', '访视常见问题', 1, true, '2025-01-10 08:00:00+00', '2025-01-10 08:00:00+00'),
    ('8888aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '用药相关', '用药与回收问题', 2, true, '2025-01-10 08:10:00+00', '2025-01-10 08:10:00+00')
ON CONFLICT (study_id, name) DO UPDATE SET
    description = EXCLUDED.description,
    sort_order = EXCLUDED.sort_order,
    is_active = EXCLUDED.is_active,
    updated_at = EXCLUDED.updated_at;

INSERT INTO public.faq_items (
    id, study_id, category_id, best_reply_id, status, resolved_by_confirm, question, answer, keywords, version, is_active, created_by, created_at, updated_at
) VALUES
    ('9999aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '7777aaaa-2222-3333-4444-555555555555', NULL, 'PENDING', false, 'V1 访视需要携带什么？', '携带知情同意书、病历及用药记录本。', '访视,携带物品', 1, true, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-10 09:00:00+00', '2025-01-10 09:00:00+00'),
    ('aaaa9999-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '7777aaaa-2222-3333-4444-555555555555', NULL, 'PENDING', false, '访视延迟是否需要重新排期？', '若延迟超过窗口期需重新安排并备注原因。', '访视,窗口期', 1, true, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-11 09:00:00+00', '2025-01-11 09:00:00+00'),
    ('bbbb9999-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '8888aaaa-2222-3333-4444-555555555555', NULL, 'PENDING', false, '药品回收需要哪些材料？', '需提供回收清单、交接单及冷链记录。', '回收,交接单', 1, true, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 09:00:00+00', '2025-01-12 09:00:00+00'),
    ('cccc9999-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '8888aaaa-2222-3333-4444-555555555555', NULL, 'PENDING', false, '药品签收后如何登记？', '签收后在药品流向中登记并上传快递单。', '药品,签收', 1, true, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-13 09:00:00+00', '2025-01-13 09:00:00+00'),
    ('dddd9999-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '7777aaaa-2222-3333-4444-555555555555', NULL, 'PENDING', false, '随访资料上传时间要求？', '访视结束 24 小时内上传。', '随访,资料上传', 1, true, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-14 09:00:00+00', '2025-01-14 09:00:00+00')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.faq_replies (
    id, faq_id, study_id, content, created_by, created_at, quote_reply_id, is_deleted
) VALUES
    ('eeee9999-2222-3333-4444-555555555555', '9999aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '如有特殊情况请提前沟通 PM。', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-10 10:00:00+00', NULL, false),
    ('ffff9999-2222-3333-4444-555555555555', 'bbbb9999-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '回收材料可在下载中心获取模板。', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 10:00:00+00', NULL, false)
ON CONFLICT (id) DO NOTHING;

UPDATE public.faq_items
SET best_reply_id = 'eeee9999-2222-3333-4444-555555555555'
WHERE id = '9999aaaa-2222-3333-4444-555555555555'
  AND best_reply_id IS NULL;

UPDATE public.faq_items
SET best_reply_id = 'ffff9999-2222-3333-4444-555555555555'
WHERE id = 'bbbb9999-2222-3333-4444-555555555555'
  AND best_reply_id IS NULL;

INSERT INTO public.attachments (
    id, study_id, entity_type, entity_id, filename, file_path, file_size, content_type, uploaded_by, uploaded_at, is_deleted
) VALUES
    ('aaaa0000-1111-2222-3333-444455556666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'finance_contract', '77777777-aaaa-bbbb-cccc-111111111111', 'contract_beijing.pdf', '/code/app/uploads/study_aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/finance_contract_77777777-aaaa-bbbb-cccc-111111111111/contract_beijing.pdf', 1024, 'application/pdf', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-08 10:00:00+00', false),
    ('bbbb0000-1111-2222-3333-444455556666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'drug_shipment', 'aaaa1111-2222-3333-4444-555555555555', 'shipment_beijing.pdf', '/code/app/uploads/study_aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/drug_shipment_aaaa1111-2222-3333-4444-555555555555/shipment_beijing.pdf', 2048, 'application/pdf', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-12 12:00:00+00', false),
    ('cccc0000-1111-2222-3333-444455556666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'startup_ethics', '1111aaaa-2222-3333-4444-555555555555', 'ethics_beijing.pdf', '/code/app/uploads/study_aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/startup_ethics_1111aaaa-2222-3333-4444-555555555555/ethics_beijing.pdf', 1536, 'application/pdf', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-20 12:00:00+00', false),
    ('dddd0000-1111-2222-3333-444455556666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'knowledge_note', '4444aaaa-2222-3333-4444-555555555555', 'note_sample.txt', '/code/app/uploads/study_aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/knowledge_note_4444aaaa-2222-3333-4444-555555555555/note_sample.txt', 512, 'text/plain', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 19:00:00+00', false)
ON CONFLICT (id) DO NOTHING;

-- =========================================
-- Document version management module
-- =========================================

DO $$
BEGIN
    CREATE TYPE public.document_scope_type AS ENUM ('GLOBAL', 'SITE', 'DERIVED');
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

DO $$
BEGIN
    CREATE TYPE public.document_status AS ENUM ('DRAFT', 'ACTIVE', 'ARCHIVED');
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

DO $$
BEGIN
    CREATE TYPE public.document_version_status AS ENUM (
        'DRAFT', 'SUBMITTED', 'APPROVED', 'EFFECTIVE', 'SUPERSEDED', 'ARCHIVED', 'WITHDRAWN'
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

DO $$
BEGIN
    CREATE TYPE public.workflow_status AS ENUM ('PENDING', 'APPROVED', 'REJECTED', 'CANCELED');
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

DO $$
BEGIN
    CREATE TYPE public.workflow_action_type AS ENUM ('SUBMIT', 'APPROVE', 'REJECT');
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

DO $$
BEGIN
    CREATE TYPE public.distribution_target_type AS ENUM ('SITE', 'ROLE', 'USER');
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

DO $$
BEGIN
    CREATE TYPE public.distribution_status AS ENUM ('ACTIVE', 'CLOSED');
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

DO $$
BEGIN
    CREATE TYPE public.acknowledgement_type AS ENUM ('RECEIVED', 'READ', 'TRAINED');
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

CREATE TABLE IF NOT EXISTS public.documents (
    id uuid PRIMARY KEY,
    trial_id uuid NOT NULL,
    site_id uuid,
    doc_no character varying(50) NOT NULL,
    doc_type character varying(50) NOT NULL,
    title character varying(200) NOT NULL,
    scope_type public.document_scope_type NOT NULL DEFAULT 'GLOBAL',
    owner_id uuid,
    status public.document_status NOT NULL DEFAULT 'ACTIVE',
    current_effective_version_id uuid,
    description text,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT uq_documents_trial_doc_no UNIQUE (trial_id, doc_no),
    CONSTRAINT fk_documents_trial_id FOREIGN KEY (trial_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_documents_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE SET NULL,
    CONSTRAINT fk_documents_owner_id FOREIGN KEY (owner_id) REFERENCES public.users(id) ON DELETE SET NULL
);

CREATE TABLE IF NOT EXISTS public.workflow_templates (
    id uuid PRIMARY KEY,
    trial_id uuid,
    name character varying(200) NOT NULL,
    description text,
    is_active boolean NOT NULL DEFAULT true,
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_workflow_templates_trial_id FOREIGN KEY (trial_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
    CONSTRAINT fk_workflow_templates_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE SET NULL
);

CREATE TABLE IF NOT EXISTS public.workflow_nodes (
    id uuid PRIMARY KEY,
    template_id uuid NOT NULL,
    node_order integer NOT NULL,
    role character varying(50) NOT NULL,
    name character varying(100),
    is_required boolean NOT NULL DEFAULT true,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT uq_workflow_nodes_order UNIQUE (template_id, node_order),
    CONSTRAINT fk_workflow_nodes_template_id FOREIGN KEY (template_id) REFERENCES public.workflow_templates(id) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS public.document_versions (
    id uuid PRIMARY KEY,
    document_id uuid NOT NULL,
    version_no character varying(50) NOT NULL,
    parent_version_id uuid,
    derived_from_version_id uuid,
    status public.document_version_status NOT NULL DEFAULT 'DRAFT',
    effective_at timestamp with time zone,
    superseded_at timestamp with time zone,
    file_uri character varying(500) NOT NULL,
    file_hash character varying(128) NOT NULL,
    file_size bigint NOT NULL,
    mime_type character varying(100),
    change_summary text,
    created_by uuid,
    submitted_at timestamp with time zone,
    approved_at timestamp with time zone,
    withdrawn_at timestamp with time zone,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT uq_document_versions_doc_no UNIQUE (document_id, version_no),
    CONSTRAINT fk_document_versions_document_id FOREIGN KEY (document_id) REFERENCES public.documents(id) ON DELETE CASCADE,
    CONSTRAINT fk_document_versions_parent_id FOREIGN KEY (parent_version_id) REFERENCES public.document_versions(id) ON DELETE SET NULL,
    CONSTRAINT fk_document_versions_derived_id FOREIGN KEY (derived_from_version_id) REFERENCES public.document_versions(id) ON DELETE SET NULL,
    CONSTRAINT fk_document_versions_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE SET NULL
);

DO $$
BEGIN
    ALTER TABLE public.documents
        ADD CONSTRAINT fk_documents_current_effective_version_id
        FOREIGN KEY (current_effective_version_id)
        REFERENCES public.document_versions(id)
        ON DELETE SET NULL;
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

CREATE TABLE IF NOT EXISTS public.version_workflows (
    id uuid PRIMARY KEY,
    document_id uuid NOT NULL,
    version_id uuid NOT NULL,
    template_id uuid NOT NULL,
    status public.workflow_status NOT NULL DEFAULT 'PENDING',
    current_node integer,
    submitted_by uuid,
    submitted_at timestamp with time zone,
    completed_at timestamp with time zone,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT uq_version_workflow_version UNIQUE (version_id),
    CONSTRAINT fk_version_workflows_document_id FOREIGN KEY (document_id) REFERENCES public.documents(id) ON DELETE CASCADE,
    CONSTRAINT fk_version_workflows_version_id FOREIGN KEY (version_id) REFERENCES public.document_versions(id) ON DELETE CASCADE,
    CONSTRAINT fk_version_workflows_template_id FOREIGN KEY (template_id) REFERENCES public.workflow_templates(id) ON DELETE RESTRICT,
    CONSTRAINT fk_version_workflows_submitted_by FOREIGN KEY (submitted_by) REFERENCES public.users(id) ON DELETE SET NULL
);

CREATE TABLE IF NOT EXISTS public.workflow_actions (
    id uuid PRIMARY KEY,
    workflow_id uuid NOT NULL,
    node_order integer,
    action public.workflow_action_type NOT NULL,
    actor_id uuid,
    comment text,
    acted_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_workflow_actions_workflow_id FOREIGN KEY (workflow_id) REFERENCES public.version_workflows(id) ON DELETE CASCADE,
    CONSTRAINT fk_workflow_actions_actor_id FOREIGN KEY (actor_id) REFERENCES public.users(id) ON DELETE SET NULL
);

CREATE TABLE IF NOT EXISTS public.distributions (
    id uuid PRIMARY KEY,
    document_id uuid NOT NULL,
    version_id uuid NOT NULL,
    target_type public.distribution_target_type NOT NULL,
    target_id character varying(50) NOT NULL,
    status public.distribution_status NOT NULL DEFAULT 'ACTIVE',
    due_at timestamp with time zone,
    closed_at timestamp with time zone,
    created_by uuid,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT fk_distributions_document_id FOREIGN KEY (document_id) REFERENCES public.documents(id) ON DELETE CASCADE,
    CONSTRAINT fk_distributions_version_id FOREIGN KEY (version_id) REFERENCES public.document_versions(id) ON DELETE CASCADE,
    CONSTRAINT fk_distributions_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE SET NULL
);

CREATE TABLE IF NOT EXISTS public.acknowledgements (
    id uuid PRIMARY KEY,
    distribution_id uuid NOT NULL,
    user_id uuid NOT NULL,
    site_id uuid,
    ack_type public.acknowledgement_type NOT NULL,
    due_at timestamp with time zone,
    acked_at timestamp with time zone,
    note text,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT uq_ack_distribution_user_type UNIQUE (distribution_id, user_id, ack_type),
    CONSTRAINT fk_acknowledgements_distribution_id FOREIGN KEY (distribution_id) REFERENCES public.distributions(id) ON DELETE CASCADE,
    CONSTRAINT fk_acknowledgements_user_id FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE RESTRICT,
    CONSTRAINT fk_acknowledgements_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE SET NULL
);

CREATE UNIQUE INDEX IF NOT EXISTS ix_documents_trial_doc_no ON public.documents (trial_id, doc_no);
CREATE INDEX IF NOT EXISTS ix_documents_site_id ON public.documents (site_id);
CREATE UNIQUE INDEX IF NOT EXISTS ix_document_versions_doc_no ON public.document_versions (document_id, version_no);
CREATE INDEX IF NOT EXISTS ix_document_versions_status ON public.document_versions (document_id, status);
CREATE UNIQUE INDEX IF NOT EXISTS uq_document_versions_pending ON public.document_versions (document_id)
    WHERE status IN ('SUBMITTED', 'APPROVED');
CREATE UNIQUE INDEX IF NOT EXISTS uq_document_pending_workflow ON public.version_workflows (document_id)
    WHERE status IN ('PENDING', 'APPROVED');
CREATE INDEX IF NOT EXISTS ix_distributions_version_target ON public.distributions (version_id, target_type, target_id);
CREATE INDEX IF NOT EXISTS ix_acknowledgements_distribution_type ON public.acknowledgements (distribution_id, ack_type);
CREATE INDEX IF NOT EXISTS ix_audit_logs_entity_at ON public.audit_logs (entity_type, entity_id, created_at);

-- =========================================
-- Demo data for document version management
-- =========================================

INSERT INTO public.workflow_templates (
    id, trial_id, name, description, is_active, created_by, created_at, updated_at
) VALUES
    (
        '11111111-aaaa-bbbb-cccc-111111111111',
        (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
        '标准审批（PM 单签）',
        'PM 单节点审批，适用于一般文件',
        true,
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '2025-01-07 08:00:00+00',
        '2025-01-07 08:00:00+00'
    ),
    (
        '11111111-aaaa-bbbb-cccc-111111111112',
        (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
        '严格审批（CRA→PM→QA）',
        '三节点审批，适用于关键文件',
        true,
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '2025-01-07 08:20:00+00',
        '2025-01-07 08:20:00+00'
    )
ON CONFLICT (id) DO UPDATE
SET name = EXCLUDED.name,
    description = EXCLUDED.description,
    is_active = EXCLUDED.is_active,
    trial_id = EXCLUDED.trial_id,
    created_by = EXCLUDED.created_by,
    updated_at = EXCLUDED.updated_at;

INSERT INTO public.workflow_nodes (
    id, template_id, node_order, role, name, is_required, created_at
) VALUES
    (
        '22222222-aaaa-bbbb-cccc-222222222222',
        '11111111-aaaa-bbbb-cccc-111111111111',
        1,
        'PM',
        '项目经理审批',
        true,
        '2025-01-07 08:10:00+00'
    ),
    (
        '22222222-aaaa-bbbb-cccc-222222222223',
        '11111111-aaaa-bbbb-cccc-111111111112',
        1,
        'CRA',
        'CRA 初审',
        true,
        '2025-01-07 08:30:00+00'
    ),
    (
        '22222222-aaaa-bbbb-cccc-222222222224',
        '11111111-aaaa-bbbb-cccc-111111111112',
        2,
        'PM',
        '项目经理复审',
        true,
        '2025-01-07 08:40:00+00'
    ),
    (
        '22222222-aaaa-bbbb-cccc-222222222225',
        '11111111-aaaa-bbbb-cccc-111111111112',
        3,
        'QA',
        'QA 终审',
        true,
        '2025-01-07 08:50:00+00'
    )
ON CONFLICT (id) DO UPDATE
SET template_id = EXCLUDED.template_id,
    node_order = EXCLUDED.node_order,
    role = EXCLUDED.role,
    name = EXCLUDED.name,
    is_required = EXCLUDED.is_required;

INSERT INTO public.documents (
    id, trial_id, site_id, doc_no, doc_type, title, scope_type, owner_id, status, current_effective_version_id, description, created_at, updated_at
) VALUES
    (
        '33333333-aaaa-bbbb-cccc-333333333333',
        (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
        NULL,
        'SOP-001',
        'SOP',
        '中心文件管理 SOP',
        'GLOBAL',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        'ACTIVE',
        NULL,
        'Demo SOP document',
        '2025-01-08 09:00:00+00',
        '2025-01-12 09:00:00+00'
    ),
    (
        '44444444-aaaa-bbbb-cccc-444444444444',
        (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
        NULL,
        'TRN-101',
        'Training',
        '中心培训材料',
        'GLOBAL',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        'ACTIVE',
        NULL,
        'Training deck',
        '2025-01-08 10:00:00+00',
        '2025-01-10 10:00:00+00'
    ),
    (
        '55555555-aaaa-bbbb-cccc-555555555555',
        (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
        (SELECT id FROM public.sites WHERE name = '北京协和医院' AND study_id = (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS')),
        'SITE-SOP-001',
        'SOP',
        '北京协和中心 SOP',
        'SITE',
        (SELECT id FROM public.users WHERE email = 'cra@example.com'),
        'ACTIVE',
        NULL,
        'Beijing site SOP',
        '2025-01-09 09:00:00+00',
        '2025-01-12 09:00:00+00'
    )
ON CONFLICT (trial_id, doc_no) DO NOTHING;

INSERT INTO public.document_versions (
    id, document_id, version_no, parent_version_id, derived_from_version_id, status, effective_at, superseded_at,
    file_uri, file_hash, file_size, mime_type, change_summary, created_by, submitted_at, approved_at, withdrawn_at, created_at
) VALUES
    (
        '55555555-aaaa-bbbb-cccc-555555555555',
        '33333333-aaaa-bbbb-cccc-333333333333',
        '1.0',
        NULL,
        NULL,
        'EFFECTIVE',
        '2025-01-10 09:00:00+00',
        NULL,
        '/code/app/uploads/documents/demo/SOP-001-v1.pdf',
        'b7c52b35f0b8e4a3c6d5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3',
        2048,
        'application/pdf',
        '首次发布',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '2025-01-09 09:00:00+00',
        '2025-01-10 08:30:00+00',
        NULL,
        '2025-01-08 09:30:00+00'
    ),
    (
        '66666666-aaaa-bbbb-cccc-666666666666',
        '33333333-aaaa-bbbb-cccc-333333333333',
        '1.1',
        '55555555-aaaa-bbbb-cccc-555555555555',
        NULL,
        'APPROVED',
        NULL,
        NULL,
        '/code/app/uploads/documents/demo/SOP-001-v1.1.pdf',
        'c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4',
        3072,
        'application/pdf',
        '小幅更新',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '2025-01-12 10:00:00+00',
        '2025-01-12 11:00:00+00',
        NULL,
        '2025-01-12 09:30:00+00'
    ),
    (
        '77777777-aaaa-bbbb-cccc-777777777777',
        '44444444-aaaa-bbbb-cccc-444444444444',
        '1.0',
        NULL,
        NULL,
        'DRAFT',
        NULL,
        NULL,
        '/code/app/uploads/documents/demo/TRN-101-v1.pdf',
        'd2c1b0a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1',
        4096,
        'application/pdf',
        '培训材料草稿',
        (SELECT id FROM public.users WHERE email = 'cra@example.com'),
        NULL,
        NULL,
        NULL,
        '2025-01-10 10:30:00+00'
    ),
    (
        '88888888-aaaa-bbbb-cccc-888888888888',
        '55555555-aaaa-bbbb-cccc-555555555555',
        '1.0',
        NULL,
        NULL,
        'EFFECTIVE',
        '2025-01-10 09:00:00+00',
        NULL,
        '/code/app/uploads/documents/demo/SITE-SOP-001-v1.pdf',
        'a3b2c1d0e9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2',
        2048,
        'application/pdf',
        '分中心 SOP 首版',
        (SELECT id FROM public.users WHERE email = 'cra@example.com'),
        '2025-01-09 09:30:00+00',
        '2025-01-10 08:30:00+00',
        NULL,
        '2025-01-09 09:00:00+00'
    )
ON CONFLICT (document_id, version_no) DO NOTHING;

UPDATE public.documents
SET current_effective_version_id = '55555555-aaaa-bbbb-cccc-555555555555',
    updated_at = '2025-01-12 09:00:00+00'
WHERE id = '33333333-aaaa-bbbb-cccc-333333333333'
  AND current_effective_version_id IS NULL;

UPDATE public.documents
SET current_effective_version_id = '88888888-aaaa-bbbb-cccc-888888888888',
    updated_at = '2025-01-10 09:10:00+00'
WHERE id = '55555555-aaaa-bbbb-cccc-555555555555'
  AND current_effective_version_id IS NULL;

INSERT INTO public.version_workflows (
    id, document_id, version_id, template_id, status, current_node, submitted_by, submitted_at, completed_at, created_at, updated_at
) VALUES
    (
        '88888888-aaaa-bbbb-cccc-888888888888',
        '33333333-aaaa-bbbb-cccc-333333333333',
        '66666666-aaaa-bbbb-cccc-666666666666',
        '11111111-aaaa-bbbb-cccc-111111111111',
        'APPROVED',
        1,
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '2025-01-12 10:00:00+00',
        '2025-01-12 11:00:00+00',
        '2025-01-12 10:00:00+00',
        '2025-01-12 11:00:00+00'
    )
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.workflow_actions (
    id, workflow_id, node_order, action, actor_id, comment, acted_at
) VALUES
    (
        '99999999-aaaa-bbbb-cccc-999999999999',
        '88888888-aaaa-bbbb-cccc-888888888888',
        1,
        'SUBMIT',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '提交审批',
        '2025-01-12 10:00:00+00'
    ),
    (
        'aaaa0000-bbbb-cccc-dddd-111111111111',
        '88888888-aaaa-bbbb-cccc-888888888888',
        1,
        'APPROVE',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '批准通过',
        '2025-01-12 11:00:00+00'
    )
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.distributions (
    id, document_id, version_id, target_type, target_id, status, due_at, closed_at, created_by, created_at
) VALUES
    (
        'bbbb0000-1111-2222-3333-444444444444',
        '33333333-aaaa-bbbb-cccc-333333333333',
        '55555555-aaaa-bbbb-cccc-555555555555',
        'SITE',
        'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
        'ACTIVE',
        '2025-01-20 18:00:00+00',
        NULL,
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '2025-01-12 12:00:00+00'
    ),
    (
        'cccc0000-1111-2222-3333-555555555555',
        '33333333-aaaa-bbbb-cccc-333333333333',
        '55555555-aaaa-bbbb-cccc-555555555555',
        'SITE',
        'cccccccc-cccc-cccc-cccc-cccccccccccc',
        'ACTIVE',
        '2025-01-20 18:00:00+00',
        NULL,
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '2025-01-12 12:05:00+00'
    ),
    (
        'dddd0000-1111-2222-3333-666666666666',
        '33333333-aaaa-bbbb-cccc-333333333333',
        '55555555-aaaa-bbbb-cccc-555555555555',
        'USER',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        'ACTIVE',
        '2025-01-20 18:00:00+00',
        NULL,
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '2025-01-12 12:10:00+00'
    ),
    (
        'eeee0000-1111-2222-3333-777777777777',
        '33333333-aaaa-bbbb-cccc-333333333333',
        '55555555-aaaa-bbbb-cccc-555555555555',
        'USER',
        (SELECT id FROM public.users WHERE email = 'cra@example.com'),
        'ACTIVE',
        '2025-01-20 18:00:00+00',
        NULL,
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        '2025-01-12 12:15:00+00'
    )
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.acknowledgements (
    id, distribution_id, user_id, site_id, ack_type, due_at, acked_at, note, created_at
) VALUES
    (
        'ffff0000-1111-2222-3333-888888888888',
        'dddd0000-1111-2222-3333-666666666666',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        NULL,
        'RECEIVED',
        '2025-01-20 18:00:00+00',
        '2025-01-12 13:00:00+00',
        '已收到',
        '2025-01-12 13:00:00+00'
    ),
    (
        '11110000-2222-3333-4444-999999999999',
        'eeee0000-1111-2222-3333-777777777777',
        (SELECT id FROM public.users WHERE email = 'cra@example.com'),
        NULL,
        'READ',
        '2025-01-20 18:00:00+00',
        '2025-01-12 14:00:00+00',
        '已阅读',
        '2025-01-12 14:00:00+00'
    )
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.audit_logs (
    id, study_id, entity_type, entity_id, action, detail, operator_id, operator_role, created_at
) VALUES
    (
        '22220000-3333-4444-5555-aaaaaaaaaaaa',
        (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
        'DOCUMENT',
        '33333333-aaaa-bbbb-cccc-333333333333',
        'DOCUMENT_CREATED',
        '{"before":null,"after":{"doc_no":"SOP-001","status":"ACTIVE"}}',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        'PM',
        '2025-01-08 09:00:00+00'
    ),
    (
        '33330000-4444-5555-6666-bbbbbbbbbbbb',
        (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
        'DOCUMENT_VERSION',
        '55555555-aaaa-bbbb-cccc-555555555555',
        'VERSION_EFFECTIVE',
        '{"before":{"status":"APPROVED"},"after":{"status":"EFFECTIVE"}}',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        'PM',
        '2025-01-10 09:00:00+00'
    ),
    (
        '44440000-5555-6666-7777-cccccccccccc',
        (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
        'DISTRIBUTION',
        'bbbb0000-1111-2222-3333-444444444444',
        'DISTRIBUTION_CREATED',
        '{"version_id":"55555555-aaaa-bbbb-cccc-555555555555","target_id":"bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"}',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        'PM',
        '2025-01-12 12:00:00+00'
    ),
    (
        '55550000-6666-7777-8888-dddddddddddd',
        (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
        'ACKNOWLEDGEMENT',
        'ffff0000-1111-2222-3333-888888888888',
        'ACK_CREATED',
        '{"distribution_id":"dddd0000-1111-2222-3333-666666666666","ack_type":"RECEIVED"}',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        'PM',
        '2025-01-12 13:00:00+00'
    )
ON CONFLICT (id) DO NOTHING;

-- Demo transition: v1.1 effective, v1.0 superseded
UPDATE public.document_versions
SET status = 'SUPERSEDED',
    superseded_at = '2025-01-15 09:00:00+00'
WHERE id = '55555555-aaaa-bbbb-cccc-555555555555'
  AND status = 'EFFECTIVE';

UPDATE public.document_versions
SET status = 'EFFECTIVE',
    effective_at = '2025-01-15 09:00:00+00'
WHERE id = '66666666-aaaa-bbbb-cccc-666666666666'
  AND status = 'APPROVED';

UPDATE public.documents
SET current_effective_version_id = '66666666-aaaa-bbbb-cccc-666666666666',
    updated_at = '2025-01-15 09:00:00+00'
WHERE id = '33333333-aaaa-bbbb-cccc-333333333333';

-- Lightweight demo: one extra draft document
INSERT INTO public.documents (
    id, trial_id, site_id, doc_no, doc_type, title, scope_type, owner_id, status, current_effective_version_id, description, created_at, updated_at
) VALUES
    (
        '99999999-eeee-ffff-aaaa-000000000001',
        (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
        NULL,
        'QRG-001',
        'Guidance',
        '研究快速指引',
        'GLOBAL',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        'ACTIVE',
        NULL,
        'Quick reference guide (draft)',
        '2025-01-16 09:00:00+00',
        '2025-01-16 09:00:00+00'
    )
ON CONFLICT (trial_id, doc_no) DO NOTHING;

INSERT INTO public.document_versions (
    id, document_id, version_no, parent_version_id, derived_from_version_id, status, effective_at, superseded_at,
    file_uri, file_hash, file_size, mime_type, change_summary, created_by, submitted_at, approved_at, withdrawn_at, created_at
) VALUES
    (
        '99999999-eeee-ffff-aaaa-000000000002',
        '99999999-eeee-ffff-aaaa-000000000001',
        '0.1',
        NULL,
        NULL,
        'DRAFT',
        NULL,
        NULL,
        '/code/app/uploads/documents/demo/QRG-001-v0.1.pdf',
        'a1b2c3d4e5f60718293a4b5c6d7e8f90123456789abcdef0123456789abcdef0',
        1536,
        'application/pdf',
        '初稿',
        (SELECT id FROM public.users WHERE email = 'pm@example.com'),
        NULL,
        NULL,
        NULL,
        '2025-01-16 09:10:00+00'
    )
ON CONFLICT (document_id, version_no) DO NOTHING;
