-- IT Glue asset audit + write-back tables.
-- See docs/wulf-pulse-ticket-analyzer-build-notes.md → Phase 4.
--
-- Two tables:
--   1. itglue_asset_audits  — one row per audit run (LLM gap analysis).
--   2. itglue_writes        — one row per write attempt (one field, one moment),
--                              with provenance back to the audit that prompted it.
--
-- A separate generic audit_log row is also written by the API layer
-- (lib/services/audit.ts) so /admin/audit-log surfaces every IT Glue change
-- alongside other admin actions. The two domain-specific tables here exist
-- because:
--   - audits accumulate full LLM context snapshots (heavy, infrequent),
--   - writes are atomic per-field decisions with before/after diffs that the
--     generic audit_log's free-form JSONB doesn't capture cleanly.

CREATE TABLE IF NOT EXISTS itglue_asset_audits (
  id                    UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  asset_type            TEXT NOT NULL CHECK (asset_type IN ('flexible_asset')),
  asset_id              BIGINT NOT NULL,
  asset_type_id         BIGINT,
  organization_id       BIGINT,
  generated_by_user_id  TEXT REFERENCES "user"(id) ON DELETE SET NULL,
  generated_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  provider              TEXT NOT NULL DEFAULT 'anthropic'
                          CHECK (provider IN ('anthropic','openrouter')),
  model_used            TEXT,
  asset_snapshot        JSONB NOT NULL,
  ticket_count          INT NOT NULL,
  field_gaps            JSONB NOT NULL,
  notes_promotions      JSONB NOT NULL,
  contradictions        JSONB NOT NULL,
  overall_score         NUMERIC(3,2),
  estimated_cost_usd    NUMERIC(10,4),
  total_input_tokens    INT,
  total_output_tokens   INT,
  status                TEXT NOT NULL DEFAULT 'complete'
                          CHECK (status IN ('pending','running','complete','failed')),
  error_message         TEXT
);

CREATE INDEX IF NOT EXISTS ix_itglue_asset_audits_asset
  ON itglue_asset_audits (asset_type, asset_id, generated_at DESC);
CREATE INDEX IF NOT EXISTS ix_itglue_asset_audits_org
  ON itglue_asset_audits (organization_id, generated_at DESC);

COMMENT ON TABLE itglue_asset_audits IS
  'One row per LLM-driven audit of an IT Glue asset against ticket history. '
  'Captures the full input snapshot (asset traits at the time, redacted), the '
  'extracted gaps/promotions/contradictions, and cost. Forever-retained.';

COMMENT ON COLUMN itglue_asset_audits.field_gaps IS
  'JSON array: [{ field_name, why_missing_matters, suggested_value, '
  'evidence_ticket_numbers, confidence }]';
COMMENT ON COLUMN itglue_asset_audits.notes_promotions IS
  'JSON array: [{ quoted_note_text, target_field, suggested_value, confidence }]';
COMMENT ON COLUMN itglue_asset_audits.contradictions IS
  'JSON array: [{ description, evidence }]';

CREATE TABLE IF NOT EXISTS itglue_writes (
  id                    UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  audit_id              UUID REFERENCES itglue_asset_audits(id) ON DELETE SET NULL,
  asset_type            TEXT NOT NULL CHECK (asset_type IN ('flexible_asset')),
  asset_id              BIGINT NOT NULL,
  field_name            TEXT NOT NULL,
  before_value          JSONB,
  after_value           JSONB NOT NULL,
  performed_by_user_id  TEXT REFERENCES "user"(id) ON DELETE SET NULL,
  performed_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  status                TEXT NOT NULL
                          CHECK (status IN ('pending','committed','failed','reverted')),
  itglue_response       JSONB,
  error_message         TEXT,
  source_evidence       JSONB
);

CREATE INDEX IF NOT EXISTS ix_itglue_writes_asset
  ON itglue_writes (asset_type, asset_id, performed_at DESC);
CREATE INDEX IF NOT EXISTS ix_itglue_writes_user
  ON itglue_writes (performed_by_user_id, performed_at DESC);
CREATE INDEX IF NOT EXISTS ix_itglue_writes_audit
  ON itglue_writes (audit_id);

COMMENT ON TABLE itglue_writes IS
  'One row per write attempt to IT Glue. Pending → committed | failed | reverted. '
  'Reverts produce a new row whose before_value/after_value swap the original; '
  'the original row gets status=reverted. Forever-retained.';
