/**
 * SQLite Storage Implementation for PMO
 *
 * This is the main facade that delegates to domain-specific storage modules.
 * Uses the unified workspace.db database with pmo_ prefixed tables.
 *
 * This module now supports Drizzle ORM for type-safe queries while maintaining
 * backward compatibility with raw SQL queries during the migration period.
 */
import Database from 'better-sqlite3';
import { createDrizzleConnection } from '../../database/drizzle.js';
import { PMO_TABLES, PMO_SCHEMA_SQL, validateTicketSchema } from '../schema.js';
import { runMigrations, seedBuiltinWorkflows, seedBuiltinPhases, seedBuiltinPhaseTemplates, seedBuiltinActions, seedBuiltinTicketTemplates, seedBuiltinCategories, seedBuiltinLabels, updateBoardTimestamp, } from './base.js';
import { ProjectStorage } from './projects.js';
import { TicketStorage } from './tickets.js';
import { SubtaskStorage, AcceptanceCriteriaStorage } from './subtasks.js';
import { SpecStorage } from './specs.js';
import { EpicStorage } from './epics.js';
import { DependencyStorage } from './dependencies.js';
import { StatusStorage } from './statuses.js';
import { TemplateStorage } from './templates.js';
import { PhaseStorage } from './phases.js';
import { ActionStorage } from './actions.js';
import { ViewStorage } from './views.js';
import { RoadmapStorage } from './roadmaps.js';
import { CategoryStorage } from './categories.js';
import { LabelStorage } from './labels.js';
const T = PMO_TABLES;
export class SQLiteStorage {
    type = 'sqlite';
    db;
    drizzle;
    dbPath;
    // Domain-specific storage modules
    projectStorage;
    ticketStorage;
    subtaskStorage;
    acceptanceCriteriaStorage;
    specStorage;
    epicStorage;
    dependencyStorage;
    statusStorage;
    templateStorage;
    phaseStorage;
    actionStorage;
    viewStorage;
    roadmapStorage;
    categoryStorage;
    labelStorage;
    constructor(dbPath) {
        this.dbPath = dbPath;
        // Open database (creates if doesn't exist)
        this.db = new Database(dbPath);
        this.db.pragma('foreign_keys = ON');
        // Create Drizzle ORM connection wrapping the same database
        this.drizzle = createDrizzleConnection(this.db);
        // Create the storage context shared by all modules
        // Note: projectId is passed explicitly to operations, not stored in context
        const ctx = {
            db: this.db,
            drizzle: this.drizzle,
            updateBoardTimestamp: (projectId) => updateBoardTimestamp(this.db, projectId),
        };
        // Initialize domain-specific storage modules
        this.projectStorage = new ProjectStorage(ctx);
        this.ticketStorage = new TicketStorage(ctx);
        this.subtaskStorage = new SubtaskStorage(ctx);
        this.acceptanceCriteriaStorage = new AcceptanceCriteriaStorage(ctx);
        this.specStorage = new SpecStorage(ctx);
        this.epicStorage = new EpicStorage(ctx);
        this.dependencyStorage = new DependencyStorage(ctx);
        this.statusStorage = new StatusStorage(ctx);
        this.templateStorage = new TemplateStorage(ctx);
        this.phaseStorage = new PhaseStorage(ctx);
        this.actionStorage = new ActionStorage(ctx);
        this.viewStorage = new ViewStorage(ctx);
        this.roadmapStorage = new RoadmapStorage(ctx);
        this.categoryStorage = new CategoryStorage(ctx);
        this.labelStorage = new LabelStorage(ctx);
        // Ensure PMO tables exist
        this.ensurePMOTables();
    }
    /**
     * Get the underlying database connection.
     */
    getDatabase() {
        return this.db;
    }
    /**
     * Get the Drizzle ORM database connection for type-safe queries.
     */
    getDrizzle() {
        return this.drizzle;
    }
    /**
     * Ensure PMO tables exist in the database.
     */
    ensurePMOTables() {
        // Run migrations FIRST for existing databases
        runMigrations(this.db);
        // Create tables and indexes using shared schema
        this.db.exec(PMO_SCHEMA_SQL);
        // Seed built-in data (workflows are the source of truth for status configurations)
        seedBuiltinWorkflows(this.db);
        seedBuiltinPhases(this.db);
        seedBuiltinPhaseTemplates(this.db);
        seedBuiltinActions(this.db);
        seedBuiltinTicketTemplates(this.db);
        seedBuiltinCategories(this.db);
        seedBuiltinLabels(this.db);
        // Validate schema
        validateTicketSchema(this.db);
    }
    // ===========================================================================
    // Board Operations
    // ===========================================================================
    async init(projectId, config) {
        return this.projectStorage.init(projectId, config);
    }
    async getBoard(projectId) {
        return this.projectStorage.getBoard(projectId);
    }
    async getBoardMarkdown(projectId) {
        return this.projectStorage.getBoardMarkdown(projectId);
    }
    // ===========================================================================
    // Column Operations (columns are now workflow statuses)
    // ===========================================================================
    getColumnNames(projectId) {
        // Get project's workflow
        const project = this.db.prepare(`
      SELECT workflow_id FROM ${T.projects} WHERE id = ?
    `).get(projectId);
        const workflowId = project?.workflow_id || 'default';
        const rows = this.db.prepare(`
      SELECT name FROM ${T.workflow_statuses}
      WHERE workflow_id = ?
      ORDER BY position
    `).all(workflowId);
        return rows.map((r) => r.name);
    }
    async createColumn(projectId, name, position) {
        // Get project's workflow
        const project = this.db.prepare(`
      SELECT workflow_id FROM ${T.projects} WHERE id = ?
    `).get(projectId);
        const workflowId = project?.workflow_id || 'default';
        // Create a status in the workflow
        const status = await this.statusStorage.createStatus(workflowId, {
            name,
            category: 'unstarted', // Default category for manually created columns
            position,
        });
        return {
            id: status.id,
            name: status.name,
            position: status.position,
            tickets: [],
        };
    }
    async renameColumn(projectId, id, name) {
        const status = await this.statusStorage.updateStatus(id, { name });
        return {
            id: status.id,
            name: status.name,
            position: status.position,
            tickets: [],
        };
    }
    async moveColumn(projectId, id, position) {
        const status = await this.statusStorage.reorderStatus(id, position);
        return {
            id: status.id,
            name: status.name,
            position: status.position,
            tickets: [],
        };
    }
    async deleteColumn(projectId, id, _cascade) {
        return this.statusStorage.deleteStatus(id);
    }
    // ===========================================================================
    // Ticket Operations
    // ===========================================================================
    async createTicket(projectId, ticket) {
        return this.ticketStorage.createTicket(projectId, ticket);
    }
    async getTicket(id) {
        return this.ticketStorage.getTicket(id);
    }
    async getTicketById(id) {
        return this.ticketStorage.getTicketById(id);
    }
    async updateTicket(id, changes) {
        return this.ticketStorage.updateTicket(id, changes);
    }
    async moveTicket(projectId, id, column, position) {
        return this.ticketStorage.moveTicket(projectId, id, column, position);
    }
    async reorderTicket(id, opts) {
        return this.ticketStorage.reorderTicket(id, opts);
    }
    async moveTicketToProject(ticketId, newProjectId) {
        return this.ticketStorage.moveTicketToProject(ticketId, newProjectId);
    }
    async deleteTicket(id) {
        return this.ticketStorage.deleteTicket(id);
    }
    async listTickets(projectId, filter) {
        return this.ticketStorage.listTickets(projectId, filter);
    }
    // ===========================================================================
    // Subtask Operations
    // ===========================================================================
    async addSubtask(ticketId, title) {
        return this.subtaskStorage.addSubtask(ticketId, title);
    }
    async toggleSubtask(ticketId, subtaskId) {
        return this.subtaskStorage.toggleSubtask(ticketId, subtaskId);
    }
    async removeSubtask(ticketId, subtaskId) {
        return this.subtaskStorage.removeSubtask(ticketId, subtaskId);
    }
    // ===========================================================================
    // Acceptance Criteria Operations
    // ===========================================================================
    async addAcceptanceCriterion(ticketId, criterion) {
        return this.acceptanceCriteriaStorage.addAcceptanceCriterion(ticketId, criterion);
    }
    async removeAcceptanceCriterion(ticketId, criterionId) {
        return this.acceptanceCriteriaStorage.removeAcceptanceCriterion(ticketId, criterionId);
    }
    async clearAcceptanceCriteria(ticketId) {
        return this.acceptanceCriteriaStorage.clearAcceptanceCriteria(ticketId);
    }
    // ===========================================================================
    // Spec Operations
    // ===========================================================================
    async createSpec(spec) {
        return this.specStorage.createSpec(spec);
    }
    async getSpec(id) {
        return this.specStorage.getSpec(id);
    }
    async listSpecs(filter) {
        return this.specStorage.listSpecs(filter);
    }
    async updateSpec(id, changes) {
        return this.specStorage.updateSpec(id, changes);
    }
    async deleteSpec(id) {
        return this.specStorage.deleteSpec(id);
    }
    async linkTicketToSpec(ticketId, specId) {
        return this.specStorage.linkTicketToSpec(ticketId, specId);
    }
    async unlinkTicketFromSpec(ticketId, specId) {
        return this.specStorage.unlinkTicketFromSpec(ticketId, specId);
    }
    async getTicketsForSpec(projectId, specId) {
        return this.specStorage.getTicketsForSpec(projectId, specId);
    }
    async getSpecsForTicket(ticketId) {
        return this.specStorage.getSpecsForTicket(ticketId);
    }
    async addSpecDependency(specId, dependsOnId) {
        return this.specStorage.addSpecDependency(specId, dependsOnId);
    }
    async removeSpecDependency(specId, dependsOnId) {
        return this.specStorage.removeSpecDependency(specId, dependsOnId);
    }
    async getSpecDependencies(specId) {
        return this.specStorage.getSpecDependencies(specId);
    }
    async getSpecDependents(specId) {
        return this.specStorage.getSpecDependents(specId);
    }
    async linkProjectToSpec(projectId, specId) {
        return this.specStorage.linkProjectToSpec(projectId, specId);
    }
    async unlinkProjectFromSpec(projectId, specId) {
        return this.specStorage.unlinkProjectFromSpec(projectId, specId);
    }
    async getSpecsForProject(projectId) {
        return this.specStorage.getSpecsForProject(projectId);
    }
    async getProjectsForSpec(specId) {
        return this.specStorage.getProjectsForSpec(specId);
    }
    // ===========================================================================
    // Epic Operations
    // ===========================================================================
    async createEpic(projectId, epic) {
        return this.epicStorage.createEpic(projectId, epic);
    }
    async getEpic(id) {
        return this.epicStorage.getEpic(id);
    }
    async listEpics(projectId, filter) {
        return this.epicStorage.listEpics(projectId, filter);
    }
    async reorderEpic(projectId, epicId, newPosition) {
        return this.epicStorage.reorderEpic(projectId, epicId, newPosition);
    }
    async updateEpic(id, changes) {
        return this.epicStorage.updateEpic(id, changes);
    }
    async deleteEpic(id) {
        return this.epicStorage.deleteEpic(id);
    }
    async getTicketsForEpic(projectId, epicId) {
        return this.epicStorage.getTicketsForEpic(projectId, epicId);
    }
    async linkTicketToEpic(ticketId, epicId) {
        return this.epicStorage.linkTicketToEpic(ticketId, epicId);
    }
    async unlinkTicketFromEpic(ticketId) {
        return this.epicStorage.unlinkTicketFromEpic(ticketId);
    }
    // ===========================================================================
    // Dependency Operations
    // ===========================================================================
    async createTicketDependency(ticketId, dependsOnId, type) {
        return this.dependencyStorage.createTicketDependency(ticketId, dependsOnId, type);
    }
    async deleteTicketDependency(ticketId, dependsOnId, type) {
        return this.dependencyStorage.deleteTicketDependency(ticketId, dependsOnId, type);
    }
    async listTicketDependencies(ticketId) {
        return this.dependencyStorage.listTicketDependencies(ticketId);
    }
    async getTicketBlockers(ticketId) {
        return this.dependencyStorage.getTicketBlockers(ticketId);
    }
    async getTicketsBlockedBy(ticketId) {
        return this.dependencyStorage.getTicketsBlockedBy(ticketId);
    }
    async isTicketBlocked(ticketId) {
        return this.dependencyStorage.isTicketBlocked(ticketId);
    }
    async createSpecDependency(specId, dependsOnId, type) {
        return this.dependencyStorage.createSpecDependency(specId, dependsOnId, type);
    }
    async deleteSpecDependency(specId, dependsOnId, type) {
        return this.dependencyStorage.deleteSpecDependency(specId, dependsOnId, type);
    }
    async listSpecDependencies(specId) {
        return this.dependencyStorage.listSpecDependencies(specId);
    }
    async createEpicDependency(epicId, dependsOnId, type) {
        return this.dependencyStorage.createEpicDependency(epicId, dependsOnId, type);
    }
    async deleteEpicDependency(epicId, dependsOnId, type) {
        return this.dependencyStorage.deleteEpicDependency(epicId, dependsOnId, type);
    }
    async listEpicDependencies(epicId) {
        return this.dependencyStorage.listEpicDependencies(epicId);
    }
    async isEpicBlocked(epicId) {
        return this.dependencyStorage.isEpicBlocked(epicId);
    }
    // ===========================================================================
    // Workflow Operations
    // ===========================================================================
    async listWorkflows(filter) {
        return this.statusStorage.listWorkflows(filter);
    }
    async getWorkflow(id) {
        return this.statusStorage.getWorkflow(id);
    }
    async createWorkflow(workflow) {
        return this.statusStorage.createWorkflow(workflow);
    }
    async updateWorkflow(id, changes) {
        return this.statusStorage.updateWorkflow(id, changes);
    }
    async deleteWorkflow(id) {
        return this.statusStorage.deleteWorkflow(id);
    }
    async getProjectWorkflow(projectId) {
        return this.statusStorage.getProjectWorkflow(projectId);
    }
    // ===========================================================================
    // Workflow Status Operations
    // ===========================================================================
    async listStatuses(workflowId) {
        return this.statusStorage.listStatuses(workflowId);
    }
    async getStatus(id) {
        return this.statusStorage.getStatus(id);
    }
    async createStatus(workflowId, status) {
        return this.statusStorage.createStatus(workflowId, status);
    }
    async updateStatus(id, changes) {
        return this.statusStorage.updateStatus(id, changes);
    }
    async deleteStatus(id) {
        return this.statusStorage.deleteStatus(id);
    }
    async reorderStatus(id, newPosition) {
        return this.statusStorage.reorderStatus(id, newPosition);
    }
    async getDefaultStatus(workflowId) {
        return this.statusStorage.getDefaultStatus(workflowId);
    }
    // ===========================================================================
    // Ticket Template Operations
    // ===========================================================================
    // Note: Workflow templates have been removed. Use workflow commands directly
    // (prlt workflow list, prlt workflow create, prlt workflow switch)
    async listTicketTemplates(filter) {
        return this.templateStorage.listTicketTemplates(filter);
    }
    async getTicketTemplate(id) {
        return this.templateStorage.getTicketTemplate(id);
    }
    async createTicketTemplate(template) {
        return this.templateStorage.createTicketTemplate(template);
    }
    async createTicketTemplateFromTicket(ticketId, name, description) {
        return this.templateStorage.createTicketTemplateFromTicket(ticketId, name, description);
    }
    async updateTicketTemplate(id, changes) {
        return this.templateStorage.updateTicketTemplate(id, changes);
    }
    async deleteTicketTemplate(id) {
        return this.templateStorage.deleteTicketTemplate(id);
    }
    // ===========================================================================
    // Phase Operations
    // ===========================================================================
    async listPhases(filter) {
        return this.phaseStorage.listPhases(filter);
    }
    async getPhase(id) {
        return this.phaseStorage.getPhase(id);
    }
    async createPhase(phase) {
        return this.phaseStorage.createPhase(phase);
    }
    async updatePhase(id, changes) {
        return this.phaseStorage.updatePhase(id, changes);
    }
    async deletePhase(id) {
        return this.phaseStorage.deletePhase(id);
    }
    async reorderPhase(id, newPosition) {
        return this.phaseStorage.reorderPhase(id, newPosition);
    }
    async getDefaultPhase() {
        return this.phaseStorage.getDefaultPhase();
    }
    // ===========================================================================
    // Phase Template Operations
    // ===========================================================================
    async listPhaseTemplates(filter) {
        return this.phaseStorage.listPhaseTemplates(filter);
    }
    async getPhaseTemplate(id) {
        return this.phaseStorage.getPhaseTemplate(id);
    }
    async applyPhaseTemplate(templateId) {
        return this.phaseStorage.applyPhaseTemplate(templateId);
    }
    async savePhaseTemplate(name, description) {
        return this.phaseStorage.savePhaseTemplate(name, description);
    }
    async updatePhaseTemplate(id, changes) {
        return this.phaseStorage.updatePhaseTemplate(id, changes);
    }
    async deletePhaseTemplate(id) {
        return this.phaseStorage.deletePhaseTemplate(id);
    }
    // ===========================================================================
    // Action Operations
    // ===========================================================================
    async listActions(filter) {
        return this.actionStorage.listActions(filter);
    }
    async getAction(id) {
        return this.actionStorage.getAction(id);
    }
    async createAction(action) {
        return this.actionStorage.createAction(action);
    }
    async updateAction(id, changes) {
        return this.actionStorage.updateAction(id, changes);
    }
    async deleteAction(id) {
        return this.actionStorage.deleteAction(id);
    }
    async getSuggestedAction(category) {
        return this.actionStorage.getSuggestedAction(category);
    }
    // ===========================================================================
    // Project Operations
    // ===========================================================================
    async createProject(project) {
        return this.projectStorage.createProject(project);
    }
    async getProjectBoard(projectId) {
        return this.projectStorage.getProjectBoard(projectId);
    }
    async listProjectSummaries() {
        return this.projectStorage.listProjectSummaries();
    }
    async deleteProject(projectId) {
        return this.projectStorage.deleteProject(projectId);
    }
    async getProject(id) {
        return this.projectStorage.getProject(id);
    }
    async updateProject(id, changes) {
        return this.projectStorage.updateProject(id, changes);
    }
    async listProjects(filter) {
        return this.projectStorage.listProjects(filter);
    }
    async archiveProject(id) {
        return this.projectStorage.archiveProject(id);
    }
    async unarchiveProject(id) {
        return this.projectStorage.unarchiveProject(id);
    }
    // ===========================================================================
    // Board View Operations
    // ===========================================================================
    async listBoardViews(filter) {
        return this.viewStorage.listBoardViews(filter);
    }
    async getBoardView(id) {
        return this.viewStorage.getBoardView(id);
    }
    async createBoardView(view) {
        return this.viewStorage.createBoardView(view);
    }
    async updateBoardView(id, changes) {
        return this.viewStorage.updateBoardView(id, changes);
    }
    async deleteBoardView(id) {
        return this.viewStorage.deleteBoardView(id);
    }
    async getDefaultBoardView(projectId) {
        return this.viewStorage.getDefaultBoardView(projectId);
    }
    async getBoardWithView(projectId, viewId, filters) {
        return this.viewStorage.getBoardWithView(projectId, viewId, filters);
    }
    // ===========================================================================
    // Roadmap Operations
    // ===========================================================================
    async listRoadmaps(filter) {
        return this.roadmapStorage.listRoadmaps(filter);
    }
    async getRoadmap(id) {
        return this.roadmapStorage.getRoadmap(id);
    }
    async createRoadmap(roadmap) {
        return this.roadmapStorage.createRoadmap(roadmap);
    }
    async updateRoadmap(id, changes) {
        return this.roadmapStorage.updateRoadmap(id, changes);
    }
    async deleteRoadmap(id) {
        return this.roadmapStorage.deleteRoadmap(id);
    }
    async getDefaultRoadmap() {
        return this.roadmapStorage.getDefaultRoadmap();
    }
    async setDefaultRoadmap(id) {
        return this.roadmapStorage.setDefaultRoadmap(id);
    }
    // ===========================================================================
    // Roadmap Project Operations
    // ===========================================================================
    async listRoadmapProjects(roadmapId) {
        return this.roadmapStorage.listRoadmapProjects(roadmapId);
    }
    async addProjectToRoadmap(roadmapId, projectId, position) {
        return this.roadmapStorage.addProjectToRoadmap(roadmapId, projectId, position);
    }
    async removeProjectFromRoadmap(roadmapId, projectId) {
        return this.roadmapStorage.removeProjectFromRoadmap(roadmapId, projectId);
    }
    async reorderRoadmapProject(roadmapId, projectId, newPosition) {
        return this.roadmapStorage.reorderRoadmapProject(roadmapId, projectId, newPosition);
    }
    async getRoadmapsForProject(projectId) {
        return this.roadmapStorage.getRoadmapsForProject(projectId);
    }
    // ===========================================================================
    // Category Operations
    // ===========================================================================
    async listCategories(filter) {
        return this.categoryStorage.listCategories(filter);
    }
    async getCategory(id) {
        return this.categoryStorage.getCategory(id);
    }
    async getCategoryByName(name, type) {
        return this.categoryStorage.getCategoryByName(name, type);
    }
    async createCategory(category) {
        return this.categoryStorage.createCategory(category);
    }
    async updateCategory(id, changes) {
        return this.categoryStorage.updateCategory(id, changes);
    }
    async renameCategory(id, newName) {
        return this.categoryStorage.renameCategory(id, newName);
    }
    async deleteCategory(id) {
        return this.categoryStorage.deleteCategory(id);
    }
    async getCategoryNames(type) {
        return this.categoryStorage.getCategoryNames(type);
    }
    async isValidCategory(name, type) {
        return this.categoryStorage.isValidCategory(name, type);
    }
    // ===========================================================================
    // Label Operations
    // ===========================================================================
    async listLabelGroups(filter) {
        return this.labelStorage.listLabelGroups(filter);
    }
    async getLabelGroup(id) {
        return this.labelStorage.getLabelGroup(id);
    }
    async getLabelGroupByName(name) {
        return this.labelStorage.getLabelGroupByName(name);
    }
    async createLabelGroup(group) {
        return this.labelStorage.createLabelGroup(group);
    }
    async updateLabelGroup(id, changes) {
        return this.labelStorage.updateLabelGroup(id, changes);
    }
    async deleteLabelGroup(id) {
        return this.labelStorage.deleteLabelGroup(id);
    }
    async listLabels(filter) {
        return this.labelStorage.listLabels(filter);
    }
    async getLabel(id) {
        return this.labelStorage.getLabel(id);
    }
    async getLabelByName(name, groupId) {
        return this.labelStorage.getLabelByName(name, groupId);
    }
    async createLabel(label) {
        return this.labelStorage.createLabel(label);
    }
    async updateLabel(id, changes) {
        return this.labelStorage.updateLabel(id, changes);
    }
    async deleteLabel(id) {
        return this.labelStorage.deleteLabel(id);
    }
    async addLabelToTicket(ticketId, labelId) {
        return this.labelStorage.addLabelToTicket(ticketId, labelId);
    }
    async removeLabelFromTicket(ticketId, labelId) {
        return this.labelStorage.removeLabelFromTicket(ticketId, labelId);
    }
    async getLabelsForTicket(ticketId) {
        return this.labelStorage.getLabelsForTicket(ticketId);
    }
    async addLabelToTicketByName(ticketId, labelName) {
        return this.labelStorage.addLabelToTicketByName(ticketId, labelName);
    }
    async removeLabelFromTicketByName(ticketId, labelName) {
        return this.labelStorage.removeLabelFromTicketByName(ticketId, labelName);
    }
    // ===========================================================================
    // Sync Operations (no-op for pure SQLite)
    // ===========================================================================
    async pull() {
        return { success: true, changes: 0 };
    }
    async push() {
        return { success: true, changes: 0 };
    }
    async status() {
        return { ahead: 0, behind: 0, conflicts: false };
    }
    // ===========================================================================
    // Rebuild Operations (for git storage sync)
    // ===========================================================================
    rebuildFromBoard(board) {
        const projectId = board.id;
        const T = PMO_TABLES;
        // Clear existing tickets for current project
        this.db.prepare(`DELETE FROM ${T.tickets} WHERE project_id = ?`).run(projectId);
        const now = Date.now();
        const nowIso = new Date(now).toISOString();
        // Get or create project and its workflow
        const existingProject = this.db.prepare(`
      SELECT name, workflow_id FROM ${T.projects} WHERE id = ?
    `).get(projectId);
        const projectName = (board.name === 'Board' && existingProject?.name) ? existingProject.name : board.name;
        let workflowId = existingProject?.workflow_id;
        // If no workflow, create a project-specific one
        if (!workflowId) {
            workflowId = `workflow-${projectId}`;
            this.db.prepare(`
        INSERT OR IGNORE INTO ${T.workflows} (id, name, description, is_builtin, created_at, updated_at)
        VALUES (?, ?, ?, 0, ?, ?)
      `).run(workflowId, `${projectName} Workflow`, `Workflow for ${projectName}`, nowIso, nowIso);
        }
        // Update or insert project with workflow
        this.db.prepare(`
      INSERT OR REPLACE INTO ${T.projects} (id, name, workflow_id, updated_at)
      VALUES (?, ?, ?, ?)
    `).run(projectId, projectName, workflowId, now);
        // Create a map of column name to status id
        const statusMap = new Map();
        // Clear existing statuses for this workflow (only if not builtin)
        const workflow = this.db.prepare(`SELECT is_builtin FROM ${T.workflows} WHERE id = ?`).get(workflowId);
        if (workflow && !workflow.is_builtin) {
            this.db.prepare(`DELETE FROM ${T.workflow_statuses} WHERE workflow_id = ?`).run(workflowId);
        }
        // Create statuses from board columns (if workflow is not builtin)
        if (!workflow?.is_builtin) {
            const insertStatus = this.db.prepare(`
        INSERT OR REPLACE INTO ${T.workflow_statuses} (id, workflow_id, name, category, position, is_default, created_at)
        VALUES (?, ?, ?, ?, ?, ?, ?)
      `);
            for (const column of board.columns) {
                const statusId = `${workflowId}-${column.id}`;
                // Infer category from column name or position
                const category = this.inferCategoryFromColumnName(column.name, column.position, board.columns.length);
                const isDefault = column.position === 0 ? 1 : 0;
                insertStatus.run(statusId, workflowId, column.name, category, column.position, isDefault, nowIso);
                statusMap.set(column.name, statusId);
            }
        }
        else {
            // For builtin workflows, map column names to existing statuses
            const statuses = this.db.prepare(`
        SELECT id, name FROM ${T.workflow_statuses} WHERE workflow_id = ? ORDER BY position
      `).all(workflowId);
            for (const status of statuses) {
                statusMap.set(status.name, status.id);
            }
        }
        // Insert tickets
        const insertTicket = this.db.prepare(`
      INSERT INTO ${T.tickets} (
        id, project_id, title, description, priority, category,
        status_id, owner, assignee, spec_id,
        created_at, updated_at, last_synced_from_spec, last_synced_from_board
      )
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `);
        const insertSubtask = this.db.prepare(`
      INSERT INTO ${T.subtasks} (id, ticket_id, title, done, position)
      VALUES (?, ?, ?, ?, ?)
    `);
        const insertMeta = this.db.prepare(`
      INSERT INTO ${T.ticket_metadata} (ticket_id, key, value)
      VALUES (?, ?, ?)
    `);
        for (const column of board.columns) {
            const statusId = statusMap.get(column.name);
            for (const ticket of column.tickets) {
                // Insert ticket data with status_id
                insertTicket.run(ticket.id, projectId, ticket.title, ticket.description || null, ticket.priority || null, ticket.category || null, statusId || null, ticket.owner || null, ticket.assignee || null, ticket.specId || null, ticket.createdAt.toISOString(), ticket.updatedAt.toISOString(), ticket.lastSyncedFromSpec || null, ticket.lastSyncedFromBoard || null);
                // Subtasks
                ticket.subtasks.forEach((st, idx) => {
                    insertSubtask.run(st.id, ticket.id, st.title, st.done ? 1 : 0, idx);
                });
                // Metadata
                for (const [key, value] of Object.entries(ticket.metadata)) {
                    insertMeta.run(ticket.id, key, value);
                }
            }
        }
    }
    /**
     * Infer a status category from column name or position.
     */
    inferCategoryFromColumnName(name, position, totalColumns) {
        const lowerName = name.toLowerCase();
        // Match common column names to categories
        if (lowerName.includes('backlog') || lowerName.includes('icebox'))
            return 'backlog';
        if (lowerName.includes('ready') || lowerName.includes('todo') || lowerName.includes('to do'))
            return 'unstarted';
        if (lowerName.includes('progress') || lowerName.includes('doing') || lowerName.includes('review'))
            return 'started';
        if (lowerName.includes('done') || lowerName.includes('complete') || lowerName.includes('finished'))
            return 'completed';
        if (lowerName.includes('cancel') || lowerName.includes('won\'t'))
            return 'canceled';
        // Fallback: infer from position
        if (position === 0)
            return 'backlog';
        if (position === totalColumns - 1)
            return 'completed';
        if (position <= totalColumns / 2)
            return 'unstarted';
        return 'started';
    }
    // ===========================================================================
    // Lifecycle
    // ===========================================================================
    async close() {
        this.db.close();
    }
    // ===========================================================================
    // Cache Operations (for git storage compatibility)
    // ===========================================================================
    getCacheMetadata() {
        const mtime = this.db.prepare(`SELECT value FROM ${T.cache_metadata} WHERE key = 'boardMtime'`).get();
        const builtAt = this.db.prepare(`SELECT value FROM ${T.cache_metadata} WHERE key = 'cacheBuiltAt'`).get();
        const hash = this.db.prepare(`SELECT value FROM ${T.cache_metadata} WHERE key = 'contentHash'`).get();
        if (!mtime || !builtAt)
            return null;
        return {
            boardMtime: parseInt(mtime.value, 10),
            cacheBuiltAt: parseInt(builtAt.value, 10),
            contentHash: hash?.value,
        };
    }
    setCacheMetadata(metadata) {
        const upsert = this.db.prepare(`
      INSERT OR REPLACE INTO ${T.cache_metadata} (key, value)
      VALUES (?, ?)
    `);
        upsert.run('boardMtime', metadata.boardMtime.toString());
        upsert.run('cacheBuiltAt', metadata.cacheBuiltAt.toString());
        if (metadata.contentHash) {
            upsert.run('contentHash', metadata.contentHash);
        }
    }
    clearCache() {
        this.db.prepare(`DELETE FROM ${T.cache_metadata}`).run();
    }
}
// Re-export for backward compatibility
export { SQLiteStorage as default };
//# sourceMappingURL=index.js.map