-- Add a real foreign key from entity_facts to personas. Until now,
-- entity_facts.persona_id was a free-form string with no integrity
-- guarantee — deleting a persona orphaned its facts, which then sat
-- forever in the readable-only-via-PersonaFilter::All hive-mind view.
--
-- personas is keyed (user_id, persona_id) so the FK has to be
-- composite. That requires entity_facts to carry user_id too, which
-- has the side benefit of fixing multi-user fact leakage on the read
-- path (without it, two users with the same 'default' persona would
-- see each other's default-scoped facts).
--
-- SQLite can't ALTER TABLE to add an FK; the table-rebuild dance is
-- the only way. Pattern matches 2026-05-09's down.sql and the older
-- 2026-04-20-000000 migration.

DROP INDEX IF EXISTS idx_entity_facts_subject;
DROP INDEX IF EXISTS idx_entity_facts_predicate;
DROP INDEX IF EXISTS idx_entity_facts_status;
DROP INDEX IF EXISTS idx_entity_facts_source_photo;
DROP INDEX IF EXISTS idx_entity_facts_persona;

ALTER TABLE entity_facts RENAME TO entity_facts_old;

CREATE TABLE entity_facts (
    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    subject_entity_id INTEGER NOT NULL,
    predicate TEXT NOT NULL,
    object_entity_id INTEGER,
    object_value TEXT,
    source_photo TEXT,
    source_insight_id INTEGER,
    confidence REAL NOT NULL DEFAULT 0.6,
    status TEXT NOT NULL DEFAULT 'active',
    created_at BIGINT NOT NULL,
    persona_id TEXT NOT NULL DEFAULT 'default',
    user_id INTEGER NOT NULL DEFAULT 1,
    CONSTRAINT fk_ef_subject FOREIGN KEY (subject_entity_id) REFERENCES entities(id) ON DELETE CASCADE,
    CONSTRAINT fk_ef_object  FOREIGN KEY (object_entity_id)  REFERENCES entities(id) ON DELETE SET NULL,
    CONSTRAINT fk_ef_insight FOREIGN KEY (source_insight_id) REFERENCES photo_insights(id) ON DELETE SET NULL,
    CONSTRAINT fk_ef_persona FOREIGN KEY (user_id, persona_id) REFERENCES personas(user_id, persona_id) ON DELETE CASCADE,
    CHECK (object_entity_id IS NOT NULL OR object_value IS NOT NULL)
);

-- Backfill: assign each legacy fact to the user that owns the matching
-- persona. Built-ins are seeded per-user with the same persona_id
-- string for everyone, so MIN(user_id) deterministically picks the
-- earliest registered user (typically user 1, the operator). Custom
-- persona_ids exist for at most one user, so MIN is also unique.
-- Falls back to user_id=1 when no matching persona row exists; in that
-- case the FK below would still fail, but legacy rows shouldn't be in
-- that state because 2026-05-09 ADD COLUMN defaulted persona_id to
-- 'default', which is seeded for every user.
INSERT INTO entity_facts
    (id, subject_entity_id, predicate, object_entity_id, object_value,
     source_photo, source_insight_id, confidence, status, created_at,
     persona_id, user_id)
SELECT
    old.id,
    old.subject_entity_id,
    old.predicate,
    old.object_entity_id,
    old.object_value,
    old.source_photo,
    old.source_insight_id,
    old.confidence,
    old.status,
    old.created_at,
    old.persona_id,
    COALESCE(
        (SELECT MIN(p.user_id) FROM personas p WHERE p.persona_id = old.persona_id),
        1
    )
FROM entity_facts_old old;

DROP TABLE entity_facts_old;

CREATE INDEX idx_entity_facts_subject ON entity_facts(subject_entity_id);
CREATE INDEX idx_entity_facts_predicate ON entity_facts(predicate);
CREATE INDEX idx_entity_facts_status ON entity_facts(status);
CREATE INDEX idx_entity_facts_source_photo ON entity_facts(source_photo);
CREATE INDEX idx_entity_facts_persona ON entity_facts(persona_id);
CREATE INDEX idx_entity_facts_user_persona ON entity_facts(user_id, persona_id);
