import { handleFileInsert, handleFileUpdate } from "./file-handlers.js";
import { materializeFileDataAtCommit } from "./materialize-file-data-at-commit.js";
import { materializeFileData } from "./materialize-file-data.js";
import { selectFileData } from "./select-file-data.js";
import { selectFileLixcol } from "./select-file-lixcol.js";
import { composeFilePathFromDescriptor, composeFilePathAtCommit, } from "./descriptor-utils.js";
import {} from "./schema-definition.js";
/**
 * Applies file-related database schema, including the file_history view.
 *
 * Consumers of file_history should always scope queries with
 * lixcol_root_commit_id (and typically lixcol_depth = 0) to avoid mixing
 * multiple timelines in one result set.
 */
export function applyFileDatabaseSchema(args) {
    const engine = args.engine;
    // applied in databse itself before state because commit
    // logic writes into the licol cache
    // applyFileLixcolCacheSchema({ lix });
    engine.sqlite.createFunction({
        name: "handle_file_insert",
        arity: 7,
        xFunc: (_ctx, ...args) => {
            // Parse metadata if it's a JSON string (SQLite converts objects to strings)
            let metadata = args[3];
            if (typeof metadata === "string" && metadata !== null) {
                try {
                    metadata = JSON.parse(metadata);
                }
                catch {
                    // If parsing fails, keep as string
                }
            }
            const result = handleFileInsert({
                engine: engine,
                file: {
                    id: args[0],
                    path: args[1],
                    data: args[2],
                    metadata: metadata,
                    hidden: Boolean(args[4]),
                },
                versionId: args[5],
                untracked: Boolean(args[6]),
            });
            return result;
        },
        deterministic: false,
    });
    engine.sqlite.createFunction({
        name: "handle_file_update",
        arity: 7,
        xFunc: (_ctx, ...args) => {
            // Parse metadata if it's a JSON string (SQLite converts objects to strings)
            let metadata = args[3];
            if (typeof metadata === "string" && metadata !== null) {
                try {
                    metadata = JSON.parse(metadata);
                }
                catch {
                    // If parsing fails, keep as string
                }
            }
            const result = handleFileUpdate({
                engine: engine,
                file: {
                    id: args[0],
                    path: args[1],
                    data: args[2],
                    metadata: metadata,
                    hidden: Boolean(args[4]),
                },
                versionId: args[5],
                untracked: Boolean(args[6]),
            });
            return result;
        },
        deterministic: false,
    });
    engine.sqlite.createFunction({
        name: "materialize_file_data",
        arity: 8,
        deterministic: false,
        xFunc: (_ctx, ...args) => {
            return materializeFileData({
                engine: engine,
                file: {
                    id: args[0],
                    path: args[1],
                    metadata: args[3],
                    directory_id: args[4],
                    name: args[5],
                    extension: args[6],
                    hidden: args[7],
                },
                versionId: args[2],
            });
        },
    });
    engine.sqlite.createFunction({
        name: "select_file_data",
        arity: 8,
        deterministic: false,
        xFunc: (_ctx, ...args) => {
            return selectFileData({
                engine: engine,
                file: {
                    id: args[0],
                    path: args[1],
                    metadata: args[3],
                    directory_id: args[4],
                    name: args[5],
                    extension: args[6],
                    hidden: args[7],
                },
                versionId: args[2],
            });
        },
    });
    // Register SQL functions for lixcol metadata caching
    // Returns JSON string with {latest_change_id, latest_commit_id, created_at, updated_at}
    engine.sqlite.createFunction({
        name: "select_file_lixcol",
        arity: 2, // file_id, version_id
        deterministic: false,
        xFunc: (_ctx, ...args) => {
            const lixcol = selectFileLixcol({
                engine: engine,
                fileId: args[0],
                versionId: args[1],
            });
            // Return as JSON string so SQL can extract fields
            return JSON.stringify(lixcol);
        },
    });
    engine.sqlite.createFunction({
        name: "materialize_file_data_at_commit",
        arity: 9,
        deterministic: false,
        xFunc: (_ctx, ...args) => {
            return materializeFileDataAtCommit({
                engine: engine,
                file: {
                    id: args[0],
                    path: args[1],
                    metadata: args[4],
                    directory_id: args[5],
                    name: args[6],
                    extension: args[7],
                    hidden: args[8],
                },
                rootCommitId: args[2],
                depth: args[3],
            });
        },
    });
    engine.sqlite.createFunction({
        name: "compose_file_path",
        arity: 2,
        deterministic: false,
        xFunc: (_ctx, ...fnArgs) => {
            const fileId = fnArgs[0];
            const versionId = String(fnArgs[1]);
            return (composeFilePathFromDescriptor({
                engine,
                versionId,
                fileId,
            }) ?? null);
        },
    });
    engine.sqlite.createFunction({
        name: "compose_file_path_at_commit",
        arity: 5,
        deterministic: false,
        xFunc: (_ctx, ...fnArgs) => {
            const [dirId, name, extension, rootCommitId, depth] = fnArgs;
            return (composeFilePathAtCommit({
                engine,
                directoryId: dirId ?? null,
                name: String(name ?? ""),
                extension: extension === null || extension === undefined
                    ? null
                    : String(extension),
                rootCommitId: String(rootCommitId),
                depth: Number(depth ?? 0),
            }) ?? null);
        },
    });
    engine.sqlite.exec(`
	  CREATE VIEW IF NOT EXISTS file AS
	        SELECT 
	                id,
	                directory_id,
	                name,
                extension,
                path,
                data,
                metadata,
                hidden,
                lixcol_entity_id,
                lixcol_schema_key,
                lixcol_file_id,
                lixcol_inherited_from_version_id,
                lixcol_change_id,
                lixcol_created_at,
                lixcol_updated_at,
                lixcol_commit_id,
                lixcol_writer_key,
                lixcol_untracked,
                lixcol_metadata
        FROM file_by_version
        WHERE lixcol_version_id IN (SELECT version_id FROM active_version);

	  CREATE VIEW IF NOT EXISTS file_by_version AS
	        WITH file_rows AS (
	            SELECT
	                json_extract(fd.snapshot_content, '$.id') AS id,
	                json_extract(fd.snapshot_content, '$.directory_id') AS directory_id,
	                json_extract(fd.snapshot_content, '$.name') AS name,
	                json_extract(fd.snapshot_content, '$.extension') AS extension,
	                json_extract(fd.snapshot_content, '$.metadata') AS metadata,
	                json_extract(fd.snapshot_content, '$.hidden') AS hidden,
	                fd.entity_id,
	                fd.version_id,
	                fd.inherited_from_version_id,
	                fd.untracked,
	                fd.metadata AS change_metadata,
	                fd.change_id,
	                fd.created_at,
	                fd.updated_at,
	                fd.commit_id,
	                fd.writer_key
	            FROM state_by_version fd
	            WHERE fd.schema_key = 'lix_file_descriptor'
	        ),
	        file_rows_with_paths AS (
	            SELECT
	                file_rows.*,
	                file_path_cache.path AS cached_path,
	                COALESCE(
	                    file_path_cache.path,
	                    compose_file_path(file_rows.id, file_rows.version_id)
	                ) AS resolved_path
	            FROM file_rows
	            LEFT JOIN lix_internal_file_path_cache AS file_path_cache
	              ON file_path_cache.file_id = file_rows.id
	             AND file_path_cache.version_id = file_rows.version_id
	        ),
	        file_rows_with_lixcol AS (
	            SELECT
	                file_rows_with_paths.*,
	                cache.latest_change_id AS cache_latest_change_id,
	                cache.latest_commit_id AS cache_latest_commit_id,
	                cache.created_at AS cache_created_at,
	                cache.updated_at AS cache_updated_at,
	                cache.writer_key AS cache_writer_key,
	                CASE
	                    WHEN cache.file_id IS NULL THEN 0
	                    ELSE 1
	                END AS has_lixcol_cache,
	                CASE
	                    WHEN cache.file_id IS NULL THEN select_file_lixcol(file_rows_with_paths.id, file_rows_with_paths.version_id)
	                    ELSE NULL
	                END AS computed_lixcol_json
	            FROM file_rows_with_paths
	            LEFT JOIN lix_internal_file_lixcol_cache AS cache
	              ON cache.file_id = file_rows_with_paths.id
	             AND cache.version_id = file_rows_with_paths.version_id
	        )
	    SELECT
	            file_rows_with_lixcol.id,
	            file_rows_with_lixcol.directory_id,
	            file_rows_with_lixcol.name,
	            file_rows_with_lixcol.extension,
	            file_rows_with_lixcol.resolved_path AS path,
	            file_rows_with_lixcol.cached_path,
	            select_file_data(
	                    file_rows_with_lixcol.id,
	                    file_rows_with_lixcol.resolved_path,
	                    file_rows_with_lixcol.version_id,
	                    file_rows_with_lixcol.metadata,
	                    file_rows_with_lixcol.directory_id,
	                    file_rows_with_lixcol.name,
	                    file_rows_with_lixcol.extension,
	                    file_rows_with_lixcol.hidden
	            ) AS data,
	            file_rows_with_lixcol.metadata,
	            file_rows_with_lixcol.hidden,
	            file_rows_with_lixcol.entity_id AS lixcol_entity_id,
	            'lix_file_descriptor' AS lixcol_schema_key,
	            file_rows_with_lixcol.entity_id AS lixcol_file_id,
	            file_rows_with_lixcol.version_id AS lixcol_version_id,
	            file_rows_with_lixcol.inherited_from_version_id AS lixcol_inherited_from_version_id,
	            CASE
	                WHEN file_rows_with_lixcol.has_lixcol_cache = 1 THEN file_rows_with_lixcol.cache_latest_change_id
	                ELSE json_extract(file_rows_with_lixcol.computed_lixcol_json, '$.latest_change_id')
	            END AS lixcol_change_id,
	            CASE
	                WHEN file_rows_with_lixcol.has_lixcol_cache = 1 THEN file_rows_with_lixcol.cache_created_at
	                ELSE json_extract(file_rows_with_lixcol.computed_lixcol_json, '$.created_at')
	            END AS lixcol_created_at,
	            CASE
	                WHEN file_rows_with_lixcol.has_lixcol_cache = 1 THEN file_rows_with_lixcol.cache_updated_at
	                ELSE json_extract(file_rows_with_lixcol.computed_lixcol_json, '$.updated_at')
	            END AS lixcol_updated_at,
	            CASE
	                WHEN file_rows_with_lixcol.has_lixcol_cache = 1 THEN file_rows_with_lixcol.cache_latest_commit_id
	                ELSE json_extract(file_rows_with_lixcol.computed_lixcol_json, '$.latest_commit_id')
	            END AS lixcol_commit_id,
	            CASE
	                WHEN file_rows_with_lixcol.has_lixcol_cache = 1 THEN file_rows_with_lixcol.cache_writer_key
	                ELSE json_extract(file_rows_with_lixcol.computed_lixcol_json, '$.writer_key')
	            END AS lixcol_writer_key,
	            file_rows_with_lixcol.untracked AS lixcol_untracked,
	            file_rows_with_lixcol.change_metadata AS lixcol_metadata
	    FROM file_rows_with_lixcol;


  CREATE TRIGGER IF NOT EXISTS file_insert
  INSTEAD OF INSERT ON file
  BEGIN
      SELECT handle_file_insert(
        COALESCE(NEW.id, lix_nano_id()),
        NEW.path,
        NEW.data,
        NEW.metadata,
        COALESCE(NEW.hidden, 0),
        (SELECT version_id FROM active_version),
        COALESCE(NEW.lixcol_untracked, 0)
      );
  END;

  CREATE TRIGGER IF NOT EXISTS file_update
  INSTEAD OF UPDATE ON file
  BEGIN
      SELECT handle_file_update(
        NEW.id,
        NEW.path,
        NEW.data,
        NEW.metadata,
        COALESCE(NEW.hidden, OLD.hidden),
        (SELECT version_id FROM active_version),
        COALESCE(NEW.lixcol_untracked, 0)
      );
  END;

  CREATE TRIGGER IF NOT EXISTS file_delete
  INSTEAD OF DELETE ON file
  BEGIN
      -- Clear the file data cache
      DELETE FROM lix_internal_file_data_cache
      WHERE file_id = OLD.id
        AND version_id = (SELECT version_id FROM active_version);

      -- Clear the file path cache
      DELETE FROM lix_internal_file_path_cache
      WHERE file_id = OLD.id
        AND version_id = (SELECT version_id FROM active_version);
        
      -- Clear the file lixcol cache
      DELETE FROM lix_internal_file_lixcol_cache
      WHERE file_id = OLD.id
        AND version_id = (SELECT version_id FROM active_version);
        
      -- Delete all non-lix_file entities associated with this file first
      DELETE FROM lix_internal_state_vtable
      WHERE file_id = OLD.id
        AND version_id = (SELECT version_id FROM active_version)
        AND schema_key != 'lix_file_descriptor'
        AND snapshot_content IS NOT NULL;
        
      -- Delete the file entity itself
      DELETE FROM state_by_version
      WHERE entity_id = OLD.id
        AND schema_key = 'lix_file_descriptor'
        AND version_id = (SELECT version_id FROM active_version);
  END;

  CREATE TRIGGER IF NOT EXISTS file_by_version_insert
  INSTEAD OF INSERT ON file_by_version
  BEGIN
      SELECT handle_file_insert(
        COALESCE(NEW.id, lix_nano_id()),
        NEW.path,
        NEW.data,
        NEW.metadata,
        COALESCE(NEW.hidden, 0),
        COALESCE(NEW.lixcol_version_id, (SELECT version_id FROM active_version)),
        COALESCE(NEW.lixcol_untracked, 0)
      );
  END;

  CREATE TRIGGER IF NOT EXISTS file_by_version_update
  INSTEAD OF UPDATE ON file_by_version
  BEGIN
      SELECT handle_file_update(
        NEW.id,
        NEW.path,
        NEW.data,
        NEW.metadata,
        COALESCE(NEW.hidden, OLD.hidden),
        COALESCE(NEW.lixcol_version_id, OLD.lixcol_version_id),
        COALESCE(NEW.lixcol_untracked, 0)
      );
  END;

  CREATE TRIGGER IF NOT EXISTS file_by_version_delete
  INSTEAD OF DELETE ON file_by_version
  BEGIN
      -- Clear the file data cache
      DELETE FROM lix_internal_file_data_cache
      WHERE file_id = OLD.id
        AND version_id = OLD.lixcol_version_id;

      -- Clear the file path cache
      DELETE FROM lix_internal_file_path_cache
      WHERE file_id = OLD.id
        AND version_id = OLD.lixcol_version_id;
        
      -- Clear the file lixcol cache
      DELETE FROM lix_internal_file_lixcol_cache
      WHERE file_id = OLD.id
        AND version_id = OLD.lixcol_version_id;
        
      -- Delete all non-lix_file entities associated with this file first
      DELETE FROM lix_internal_state_vtable
      WHERE file_id = OLD.id
        AND version_id = OLD.lixcol_version_id
        AND schema_key != 'lix_file_descriptor'
        AND snapshot_content IS NOT NULL;
        
      -- Delete the file entity itself
      DELETE FROM state_by_version
      WHERE entity_id = OLD.id
        AND schema_key = 'lix_file_descriptor'
        AND version_id = OLD.lixcol_version_id;
  END;

  -- file_history exposes file snapshots per commit. When querying, always filter by
  -- lixcol_root_commit_id (and usually lixcol_depth = 0) to scope results to a single
  -- checkpoint/root commit and avoid mixing multiple timelines in one result set.
  CREATE VIEW IF NOT EXISTS file_history AS
	  WITH
	  -- Inline entity views to avoid preprocessor dependencies
	  _commit_by_version AS (
    SELECT 
      json_extract(s.snapshot_content, '$.id') AS id,
      json_extract(s.snapshot_content, '$.change_set_id') AS change_set_id,
      s.version_id AS lixcol_version_id
    FROM state_by_version AS s
    WHERE s.schema_key = 'lix_commit'
      AND s.snapshot_content IS NOT NULL
  ),
	  _change_set_element_by_version AS (
    SELECT
      json_extract(s.snapshot_content, '$.change_set_id') AS change_set_id,
      json_extract(s.snapshot_content, '$.change_id') AS change_id,
      json_extract(s.snapshot_content, '$.entity_id') AS entity_id,
      json_extract(s.snapshot_content, '$.schema_key') AS schema_key,
      json_extract(s.snapshot_content, '$.file_id') AS file_id,
      s.version_id AS lixcol_version_id
    FROM state_by_version AS s
    WHERE s.schema_key = 'lix_change_set_element'
      AND s.snapshot_content IS NOT NULL
  ),
	  descriptor_history AS (
    SELECT
      json_extract(snapshot_content, '$.id') AS id,
      json_extract(snapshot_content, '$.directory_id') AS directory_id,
      json_extract(snapshot_content, '$.name') AS name,
      json_extract(snapshot_content, '$.extension') AS extension,
      compose_file_path_at_commit(
        json_extract(snapshot_content, '$.directory_id'),
        json_extract(snapshot_content, '$.name'),
        json_extract(snapshot_content, '$.extension'),
        root_commit_id,
        depth
      ) AS path,
      materialize_file_data_at_commit(
        json_extract(snapshot_content, '$.id'),
        compose_file_path_at_commit(
          json_extract(snapshot_content, '$.directory_id'),
          json_extract(snapshot_content, '$.name'),
          json_extract(snapshot_content, '$.extension'),
          root_commit_id,
          depth
        ),
        root_commit_id,
        depth,
        json_extract(snapshot_content, '$.metadata'),
        json_extract(snapshot_content, '$.directory_id'),
        json_extract(snapshot_content, '$.name'),
        json_extract(snapshot_content, '$.extension'),
        json_extract(snapshot_content, '$.hidden')
      ) AS data,
      json_extract(snapshot_content, '$.metadata') AS metadata,
      json_extract(snapshot_content, '$.hidden') AS hidden,
      entity_id AS lixcol_entity_id,
      'lix_file_descriptor' AS lixcol_schema_key,
      'global' AS lixcol_version_id,
      file_id AS lixcol_file_id,
      plugin_key AS lixcol_plugin_key,
      schema_version AS lixcol_schema_version,
      change_id AS lixcol_change_id,
      commit_id AS lixcol_commit_id,
      root_commit_id AS lixcol_root_commit_id,
      depth AS lixcol_depth,
      metadata AS lixcol_metadata
    FROM state_history
    WHERE schema_key = 'lix_file_descriptor'
  ),
  file_changes AS (
    SELECT
      c.id AS commit_id,
      c.id AS root_commit_id,
      cse.file_id AS file_id,
      cse.change_id AS change_id,
      cse.schema_key AS schema_key,
      ch.created_at AS created_at,
      ROW_NUMBER() OVER (
        PARTITION BY c.id, cse.file_id
        ORDER BY ch.created_at DESC
      ) AS rn,
      SUM(CASE WHEN cse.schema_key = 'lix_file_descriptor' THEN 1 ELSE 0 END)
        OVER (PARTITION BY c.id, cse.file_id) AS descriptor_change_count
    FROM _commit_by_version c
    JOIN _change_set_element_by_version cse
      ON c.change_set_id = cse.change_set_id
      AND cse.lixcol_version_id = 'global'
    JOIN change ch ON ch.id = cse.change_id
    WHERE c.lixcol_version_id = 'global'
      AND cse.file_id IS NOT NULL
      AND cse.file_id != 'lix'
  ),
	  content_commits AS (
    SELECT
      commit_id,
      root_commit_id,
      file_id,
      change_id
    FROM file_changes
    WHERE descriptor_change_count = 0
      AND rn = 1
  ),
	  latest_descriptor AS (
    SELECT *
    FROM (
      SELECT
        sh.entity_id,
        sh.file_id,
        sh.plugin_key,
        sh.schema_version,
        sh.snapshot_content,
        sh.metadata,
        sh.root_commit_id,
        ROW_NUMBER() OVER (
          PARTITION BY sh.file_id, sh.root_commit_id
          ORDER BY sh.depth ASC
        ) AS rn
      FROM state_history sh
      WHERE sh.schema_key = 'lix_file_descriptor'
    )
    WHERE rn = 1
  ),
	  content_history AS (
    SELECT
      json_extract(ld.snapshot_content, '$.id') AS id,
      json_extract(ld.snapshot_content, '$.directory_id') AS directory_id,
      json_extract(ld.snapshot_content, '$.name') AS name,
      json_extract(ld.snapshot_content, '$.extension') AS extension,
      compose_file_path_at_commit(
        json_extract(ld.snapshot_content, '$.directory_id'),
        json_extract(ld.snapshot_content, '$.name'),
        json_extract(ld.snapshot_content, '$.extension'),
        sc.root_commit_id,
        0
      ) AS path,
      materialize_file_data_at_commit(
        json_extract(ld.snapshot_content, '$.id'),
        compose_file_path_at_commit(
          json_extract(ld.snapshot_content, '$.directory_id'),
          json_extract(ld.snapshot_content, '$.name'),
          json_extract(ld.snapshot_content, '$.extension'),
          sc.root_commit_id,
          0
        ),
        sc.root_commit_id,
        0,
        json_extract(ld.snapshot_content, '$.metadata'),
        json_extract(ld.snapshot_content, '$.directory_id'),
        json_extract(ld.snapshot_content, '$.name'),
        json_extract(ld.snapshot_content, '$.extension'),
        json_extract(ld.snapshot_content, '$.hidden')
      ) AS data,
      json_extract(ld.snapshot_content, '$.metadata') AS metadata,
      json_extract(ld.snapshot_content, '$.hidden') AS hidden,
      sc.file_id AS lixcol_entity_id,
      'lix_file_descriptor' AS lixcol_schema_key,
      'global' AS lixcol_version_id,
      sc.file_id AS lixcol_file_id,
      ld.plugin_key AS lixcol_plugin_key,
      ld.schema_version AS lixcol_schema_version,
      sc.change_id AS lixcol_change_id,
      sc.commit_id AS lixcol_commit_id,
      sc.root_commit_id AS lixcol_root_commit_id,
      0 AS lixcol_depth,
      ld.metadata AS lixcol_metadata
	    FROM content_commits sc
    JOIN latest_descriptor ld
      ON ld.file_id = sc.file_id
      AND ld.root_commit_id = sc.root_commit_id
  )
	  SELECT * FROM descriptor_history
	  UNION ALL
	  SELECT * FROM content_history;
`);
    // lix_internal_state_vtable is a virtual table; SQLite cannot attach indexes directly to it.
    // History queries can be optimized later with dedicated cache tables if necessary.
}
//# sourceMappingURL=schema.js.map