-- Mutable metadata feature, milestone 1.4: schema CRUD queries for
-- client_metadata_schemas. See plan Section 8.2 of
-- plans/mutable.metadata.plan.combo.v4.md for the canonical list.
--
-- Intentionally omitted in v4:
--   - GetSchemaMetadataRecordCount (removed; canDelete derives from
--     GetSchemaDocumentCount alone because document_custom_metadata has
--     no schema_id column in v4).
--   - Metadata, document-modification, and reset-metadata queries
--     (Milestones 2 and 3, plan sections 8.2 continued).

-- name: CreateClientMetadataSchema :one
-- Insert a new schema row. Caller supplies an explicit version computed
-- from GetMaxSchemaVersion + 1 and an explicit status (always 'active'
-- in Milestone 1; supersede/retire go through SetSchemaStatus). The
-- database defaults id and created_at.
INSERT INTO client_metadata_schemas (
    client_id,
    name,
    description,
    schema_def,
    version,
    status,
    created_by
) VALUES (
    @client_id,
    @name,
    @description,
    @schema_def,
    @version,
    @status,
    @created_by
)
RETURNING *;

-- name: GetClientMetadataSchema :one
-- Fetch a single schema by primary key.
SELECT * FROM client_metadata_schemas
WHERE id = $1;

-- name: ListClientMetadataSchemas :many
-- List schemas for a client with optional filters. Status filtering uses a
-- two-parameter shape: when include_all_statuses is true, status is ignored;
-- otherwise status_filter selects exactly one of active/superseded/retired.
-- When include_all_versions is false, only the latest version per
-- (client_id, name) is returned (via a max-version subquery). When true,
-- every version is returned. Name filter uses sqlc.narg so passing NULL
-- skips the filter; a non-NULL value is matched exactly. The document_count
-- column is a correlated subquery so the handler can derive canDelete
-- without a second round-trip.
SELECT
    cms.*,
    (SELECT COUNT(*) FROM documents WHERE documents.custom_schema_id = cms.id)::bigint AS document_count
FROM client_metadata_schemas cms
WHERE cms.client_id = @client_id
  AND (sqlc.narg(name_filter)::varchar IS NULL OR cms.name = sqlc.narg(name_filter)::varchar)
  AND (@include_all_statuses::bool OR cms.status = @status_filter::schema_status_type)
  AND (
        @include_all_versions::bool
        OR (cms.client_id, cms.name, cms.version) IN (
            SELECT client_id, name, MAX(version)
            FROM client_metadata_schemas
            WHERE client_id = @client_id
            GROUP BY client_id, name
        )
      )
ORDER BY cms.name, cms.version DESC
LIMIT @limit_val OFFSET @offset_val;

-- name: GetLatestSchemaByName :one
-- Return the highest-version row for a (client_id, name) pair regardless
-- of status. Callers that need an active-only view should filter after.
SELECT * FROM client_metadata_schemas
WHERE client_id = @client_id AND name = @name
ORDER BY version DESC
LIMIT 1;

-- name: GetSchemaDocumentCount :one
-- Count documents currently bound to a schema via documents.custom_schema_id.
-- Used to derive canDelete and to drive retire-vs-delete decisions.
SELECT COUNT(*) AS document_count
FROM documents
WHERE custom_schema_id = @schema_id;

-- name: SetSchemaStatus :exec
-- Update a schema's status. Used by the service layer to mark a row
-- superseded when a new version is created, and to mark a row retired
-- when the schema still has documents bound at delete time.
UPDATE client_metadata_schemas
SET status = @status
WHERE id = @id;

-- name: GetMaxSchemaVersion :one
-- Get the current max version for a (client_id, name) pair. Returns 0
-- for a brand-new pair so the service layer can safely write version 1.
-- Must be called inside the same transaction that holds the lock from
-- LockSchemaVersionsForName.
SELECT COALESCE(MAX(version), 0) AS max_version
FROM client_metadata_schemas
WHERE client_id = @client_id AND name = @name;

-- name: LockSchemaVersionsForName :many
-- Lock every version row of a (client_id, name) pair with FOR UPDATE to
-- serialize concurrent version creation. Returns the locked rows so the
-- service can read the current active row id and max version in one
-- statement. Must be called inside a transaction.
SELECT * FROM client_metadata_schemas
WHERE client_id = @client_id AND name = @name
FOR UPDATE;
