CREATE TABLE IF NOT EXISTS document_category_catalog (
  id BIGSERIAL PRIMARY KEY,
  code VARCHAR(80) NOT NULL UNIQUE,
  label VARCHAR(120) NOT NULL,
  description TEXT,
  sort_order INTEGER NOT NULL DEFAULT 1000,
  is_active BOOLEAN NOT NULL DEFAULT TRUE,
  created_by BIGINT REFERENCES app_user(id),
  updated_by BIGINT REFERENCES app_user(id),
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS public_document_setting (
  id INTEGER PRIMARY KEY DEFAULT 1,
  enabled BOOLEAN NOT NULL DEFAULT FALSE,
  intro_text TEXT NOT NULL DEFAULT 'Vom Betriebsrat freigegebene Dokumente',
  created_by BIGINT REFERENCES app_user(id),
  updated_by BIGINT REFERENCES app_user(id),
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT public_document_setting_singleton CHECK (id = 1)
);

DO $$
BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'trg_document_category_catalog_updated_at') THEN
    CREATE TRIGGER trg_document_category_catalog_updated_at
      BEFORE UPDATE ON document_category_catalog
      FOR EACH ROW EXECUTE FUNCTION set_updated_at();
  END IF;

  IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'trg_public_document_setting_updated_at') THEN
    CREATE TRIGGER trg_public_document_setting_updated_at
      BEFORE UPDATE ON public_document_setting
      FOR EACH ROW EXECUTE FUNCTION set_updated_at();
  END IF;
END $$;

ALTER TABLE document_item
  ADD COLUMN IF NOT EXISTS document_category_id BIGINT REFERENCES document_category_catalog(id);

INSERT INTO document_category_catalog(code, label, description, sort_order)
VALUES
  ('allgemein', 'Allgemein', 'Allgemeine Dokumente', 10),
  ('protokoll', 'Protokoll', 'Sitzungs- und Gesprächsprotokolle', 20),
  ('beschluss', 'Beschluss', 'Beschlussbezogene Dokumente', 30),
  ('rechnung', 'Rechnung', 'Rechnungen und Belege', 40),
  ('vertrag', 'Vertrag', 'Verträge und Vereinbarungen', 50),
  ('vorlage', 'Vorlage', 'Vorlagen und Muster', 60),
  ('oeffentlich', 'Öffentlich', 'Öffentlich freigegebene Dokumente', 70),
  ('sonstiges', 'Sonstiges', 'Sonstige Dokumente', 999)
ON CONFLICT (code) DO UPDATE
  SET label = EXCLUDED.label,
      description = EXCLUDED.description,
      sort_order = EXCLUDED.sort_order,
      is_active = TRUE;

UPDATE document_item d
   SET document_category_id = c.id
  FROM document_category_catalog c
 WHERE d.document_category_id IS NULL
   AND c.code = CASE
     WHEN lower(COALESCE(d.document_type, '')) LIKE '%protokoll%' THEN 'protokoll'
     WHEN lower(COALESCE(d.document_type, '')) LIKE '%beschluss%' THEN 'beschluss'
     WHEN lower(COALESCE(d.document_type, '')) LIKE '%rechnung%' OR lower(COALESCE(d.document_type, '')) LIKE '%beleg%' THEN 'rechnung'
     WHEN lower(COALESCE(d.document_type, '')) LIKE '%vertrag%' THEN 'vertrag'
     WHEN lower(COALESCE(d.document_type, '')) LIKE '%vorlage%' THEN 'vorlage'
     ELSE 'allgemein'
   END;

INSERT INTO public_document_setting(id, enabled, intro_text)
VALUES (1, FALSE, 'Vom Betriebsrat freigegebene Dokumente')
ON CONFLICT (id) DO NOTHING;

INSERT INTO app_page(page_key, path, label, nav_group, sort_order, description)
VALUES
  ('document_categories', '/document-categories', 'Dokumentenkategorien', 'admin', 216, 'Kategorien für Dokumente pflegen'),
  ('public_documents_admin', '/public-documents-admin', 'Öffentliche Dokumente', 'admin', 217, 'Öffentliche Dokumentenseite konfigurieren')
ON CONFLICT (page_key) DO UPDATE
  SET path = EXCLUDED.path,
      label = EXCLUDED.label,
      nav_group = EXCLUDED.nav_group,
      sort_order = EXCLUDED.sort_order,
      description = EXCLUDED.description;

INSERT INTO app_permission(permission_key, label, category, description)
VALUES
  ('document_categories.manage', 'Dokumentenkategorien verwalten', 'Administration', 'Dokumentenkategorien anlegen, bearbeiten und deaktivieren/löschen'),
  ('public_documents.configure', 'Öffentliche Dokumente konfigurieren', 'Administration', 'Öffentliche Dokumentenseite ein- und ausschalten sowie Beschreibung pflegen')
ON CONFLICT (permission_key) DO UPDATE
  SET label = EXCLUDED.label,
      category = EXCLUDED.category,
      description = EXCLUDED.description;

INSERT INTO app_role_page(role_profile_id, page_key, can_view)
SELECT id, page_key, TRUE
  FROM app_role_profile
 CROSS JOIN (VALUES ('document_categories'), ('public_documents_admin')) AS p(page_key)
 WHERE code IN ('admin', 'chair')
ON CONFLICT (role_profile_id, page_key) DO UPDATE SET can_view = TRUE;

INSERT INTO app_role_permission(role_profile_id, permission_key, granted)
SELECT id, permission_key, TRUE
  FROM app_role_profile
 CROSS JOIN (VALUES ('document_categories.manage'), ('public_documents.configure')) AS p(permission_key)
 WHERE code IN ('admin', 'chair')
ON CONFLICT (role_profile_id, permission_key) DO UPDATE SET granted = TRUE;

CREATE OR REPLACE FUNCTION app_can_read_document(target_document_id BIGINT) RETURNS BOOLEAN AS $$
DECLARE
  row document_item%ROWTYPE;
BEGIN
  SELECT * INTO row FROM document_item WHERE id = target_document_id AND deleted_at IS NULL;
  IF NOT FOUND THEN RETURN FALSE; END IF;
  IF row.scan_status <> 'clean' THEN RETURN FALSE; END IF;

  IF row.confidentiality_level = 'oeffentlich' THEN RETURN TRUE; END IF;
  IF app_role() IN ('admin', 'chair') OR app_has_permission('documents.read.all') THEN RETURN TRUE; END IF;
  IF row.uploaded_by = app_user_id() THEN RETURN TRUE; END IF;
  IF row.case_id IS NOT NULL AND app_can_read_case(row.case_id) THEN RETURN TRUE; END IF;
  IF app_user_has_document_team_access(row.id, FALSE) THEN RETURN TRUE; END IF;
  IF row.case_id IS NULL AND row.decision_id IS NULL AND row.confidentiality_level = 'intern' AND app_has_permission('documents.read.released') THEN RETURN TRUE; END IF;

  RETURN FALSE;
END;
$$ LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = public;

ALTER TABLE document_category_catalog ENABLE ROW LEVEL SECURITY;
ALTER TABLE public_document_setting ENABLE ROW LEVEL SECURITY;

DROP POLICY IF EXISTS document_category_catalog_select ON document_category_catalog;
DROP POLICY IF EXISTS document_category_catalog_modify ON document_category_catalog;
CREATE POLICY document_category_catalog_select ON document_category_catalog FOR SELECT USING (
  is_active = TRUE
  OR app_can_view_page('documents')
  OR app_can_view_page('document_categories')
  OR app_has_permission('documents.write')
  OR app_has_permission('document_categories.manage')
);
CREATE POLICY document_category_catalog_modify ON document_category_catalog FOR ALL USING (app_has_permission('document_categories.manage')) WITH CHECK (app_has_permission('document_categories.manage'));

DROP POLICY IF EXISTS public_document_setting_select ON public_document_setting;
DROP POLICY IF EXISTS public_document_setting_modify ON public_document_setting;
CREATE POLICY public_document_setting_select ON public_document_setting FOR SELECT USING (TRUE);
CREATE POLICY public_document_setting_modify ON public_document_setting FOR ALL USING (app_has_permission('public_documents.configure')) WITH CHECK (app_has_permission('public_documents.configure'));

CREATE INDEX IF NOT EXISTS idx_document_item_category ON document_item(document_category_id);
CREATE INDEX IF NOT EXISTS idx_document_item_public ON document_item(confidentiality_level, scan_status, deleted_at);

GRANT SELECT, INSERT, UPDATE, DELETE ON document_category_catalog, public_document_setting TO br_app;
GRANT USAGE, SELECT ON SEQUENCE document_category_catalog_id_seq TO br_app;
