-- ImageHub: Cloud Import — storage methods + external (referenced, not copied) dataset files.
-- A storage method holds verified credentials (config_encrypted, never returned to the client)
-- for an external bucket (S3/GCS/Azure). A dataset file is then EITHER a local content-addressed
-- blob (blob_sha256 set) OR an external reference (storage_method_id + external_path set) that
-- streams from the bucket and is never copied to our servers (privacy rule C4). Idempotent
-- (CREATE/ADD ... IF NOT EXISTS) so the startup runner can apply it to volumes that predate it.
-- Apply after 018 (no semicolons inside comments or string literals — the runner splitter is naive):
--   docker exec -i initiative-postgres psql -U initiative -d initiatives < be0/migrations/019_imagehub_cloud_import.sql

CREATE TABLE IF NOT EXISTS imagehub_storage_methods (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  owner_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  name TEXT NOT NULL,
  provider TEXT NOT NULL CHECK (provider IN ('s3','gcs','azure')),
  access_mode TEXT NOT NULL DEFAULT 'read' CHECK (access_mode IN ('read','readwrite')),
  bucket TEXT NOT NULL,
  region TEXT,
  config_encrypted TEXT NOT NULL,
  verification_status TEXT NOT NULL DEFAULT 'pending' CHECK (verification_status IN ('pending','verified','failed')),
  verification_reason TEXT,
  verification_checked_at TIMESTAMPTZ,
  created_by UUID REFERENCES users(id) ON DELETE SET NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_imagehub_storage_methods_owner
  ON imagehub_storage_methods (owner_id);

-- Allow a dataset file to be an external reference instead of a local blob. Existing rows keep
-- blob_sha256 set and the new columns NULL, so they satisfy the local-blob branch of the CHECK.
ALTER TABLE imagehub_dataset_files
  ALTER COLUMN blob_sha256 DROP NOT NULL;

ALTER TABLE imagehub_dataset_files
  ADD COLUMN IF NOT EXISTS storage_method_id UUID REFERENCES imagehub_storage_methods(id) ON DELETE RESTRICT;

ALTER TABLE imagehub_dataset_files
  ADD COLUMN IF NOT EXISTS external_path TEXT;

-- A file is EITHER a local content-addressed blob OR an external reference, never both or neither.
ALTER TABLE imagehub_dataset_files
  DROP CONSTRAINT IF EXISTS ck_imagehub_file_storage_mode;

ALTER TABLE imagehub_dataset_files
  ADD CONSTRAINT ck_imagehub_file_storage_mode CHECK (
    (blob_sha256 IS NOT NULL AND storage_method_id IS NULL AND external_path IS NULL)
    OR
    (blob_sha256 IS NULL AND storage_method_id IS NOT NULL AND external_path IS NOT NULL)
  );

CREATE INDEX IF NOT EXISTS idx_imagehub_dataset_files_storage_method
  ON imagehub_dataset_files (storage_method_id);
