import { queryWithRLS, mutateWithRLS, queryOneWithRLS, queryRows } from "../db.js";
import { extractPatternIds } from "../blocks/pattern-resolver.js";
import { entityRegistry } from "../entities/registry.js";
class PatternUsageService {
  /**
   * Sync pattern usages for an entity
   *
   * Extracts pattern references from blocks and updates the usage table.
   * Uses diff-based approach: only adds new and removes old references.
   *
   * @param entityType - Type of entity (e.g., 'pages', 'posts')
   * @param entityId - ID of the entity
   * @param teamId - Team ID for isolation
   * @param blocks - Array of blocks that may contain pattern references
   * @param userId - User ID for RLS
   */
  static async syncUsages(entityType, entityId, teamId, blocks, userId) {
    try {
      const currentPatternIds = new Set(extractPatternIds(blocks));
      const existingUsages = await queryWithRLS(
        `SELECT "patternId" FROM pattern_usages
         WHERE "entityType" = $1 AND "entityId" = $2`,
        [entityType, entityId],
        userId
      );
      const existingPatternIds = new Set(existingUsages.map((u) => u.patternId));
      const toAdd = [...currentPatternIds].filter((id) => !existingPatternIds.has(id));
      const toRemove = [...existingPatternIds].filter((id) => !currentPatternIds.has(id));
      if (toRemove.length > 0) {
        await mutateWithRLS(
          `DELETE FROM pattern_usages
           WHERE "entityType" = $1 AND "entityId" = $2 AND "patternId" = ANY($3)`,
          [entityType, entityId, toRemove],
          userId
        );
      }
      if (toAdd.length > 0) {
        const insertValues = [];
        const placeholders = [];
        let paramIndex = 1;
        for (const patternId of toAdd) {
          placeholders.push(`($${paramIndex}, $${paramIndex + 1}, $${paramIndex + 2}, $${paramIndex + 3})`);
          insertValues.push(patternId, entityType, entityId, teamId);
          paramIndex += 4;
        }
        await mutateWithRLS(
          `INSERT INTO pattern_usages ("patternId", "entityType", "entityId", "teamId")
           VALUES ${placeholders.join(", ")}
           ON CONFLICT ("patternId", "entityType", "entityId") DO NOTHING`,
          insertValues,
          userId
        );
      }
      console.log(`[PatternUsageService] Synced usages for ${entityType}/${entityId}: +${toAdd.length} -${toRemove.length}`);
    } catch (error) {
      console.error(`[PatternUsageService] Error syncing usages for ${entityType}/${entityId}:`, error);
    }
  }
  /**
   * Remove all usages for an entity (on delete)
   *
   * @param entityType - Type of entity
   * @param entityId - ID of the entity
   * @param userId - User ID for RLS
   */
  static async removeEntityUsages(entityType, entityId, userId) {
    try {
      await mutateWithRLS(
        `DELETE FROM pattern_usages
         WHERE "entityType" = $1 AND "entityId" = $2`,
        [entityType, entityId],
        userId
      );
      console.log(`[PatternUsageService] Removed usages for ${entityType}/${entityId}`);
    } catch (error) {
      console.error(`[PatternUsageService] Error removing usages for ${entityType}/${entityId}:`, error);
    }
  }
  /**
   * Get usage count for a pattern
   *
   * @param patternId - Pattern ID
   * @param userId - User ID for RLS
   * @returns Total usage count
   */
  static async getUsageCount(patternId, userId) {
    const result = await queryOneWithRLS(
      `SELECT COUNT(*)::text as count FROM pattern_usages WHERE "patternId" = $1`,
      [patternId],
      userId
    );
    return parseInt((result == null ? void 0 : result.count) || "0", 10);
  }
  /**
   * Get usage counts grouped by entity type
   *
   * @param patternId - Pattern ID
   * @param userId - User ID for RLS
   * @returns Array of counts by entity type
   */
  static async getUsageCounts(patternId, userId) {
    const results = await queryWithRLS(
      `SELECT "entityType", COUNT(*)::text as count
       FROM pattern_usages
       WHERE "patternId" = $1
       GROUP BY "entityType"
       ORDER BY count DESC`,
      [patternId],
      userId
    );
    return results.map((r) => ({
      entityType: r.entityType,
      count: parseInt(r.count, 10)
    }));
  }
  /**
   * Get detailed usages with entity information
   *
   * Joins with entity tables to get title, slug, status, etc.
   *
   * @param patternId - Pattern ID
   * @param userId - User ID for RLS
   * @param options - Filtering and pagination options
   * @returns Usages with entity info, counts, and total
   */
  static async getUsagesWithEntityInfo(patternId, userId, options = {}) {
    const { entityType, limit = 50, offset = 0 } = options;
    let whereClause = 'WHERE pu."patternId" = $1';
    const params = [patternId];
    let paramIndex = 2;
    if (entityType) {
      whereClause += ` AND pu."entityType" = $${paramIndex}`;
      params.push(entityType);
      paramIndex++;
    }
    const countResult = await queryOneWithRLS(
      `SELECT COUNT(*)::text as count FROM pattern_usages pu ${whereClause}`,
      params,
      userId
    );
    const total = parseInt((countResult == null ? void 0 : countResult.count) || "0", 10);
    const counts = await this.getUsageCounts(patternId, userId);
    const usages = await queryWithRLS(
      `SELECT pu.id, pu."patternId", pu."entityType", pu."entityId", pu."teamId", pu."createdAt"
       FROM pattern_usages pu
       ${whereClause}
       ORDER BY pu."createdAt" DESC
       LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`,
      [...params, limit, offset],
      userId
    );
    const enrichedUsages = await this.enrichUsagesWithEntityInfo(usages, userId);
    return {
      usages: enrichedUsages,
      counts,
      total
    };
  }
  /**
   * Enrich usages with entity information
   *
   * Batches queries by entity type for efficiency.
   *
   * @param usages - Array of pattern usages
   * @param userId - User ID for RLS
   * @returns Usages with entity info added
   */
  static async enrichUsagesWithEntityInfo(usages, userId) {
    if (usages.length === 0) return [];
    const usagesByType = /* @__PURE__ */ new Map();
    for (const usage of usages) {
      const existing = usagesByType.get(usage.entityType) || [];
      existing.push(usage);
      usagesByType.set(usage.entityType, existing);
    }
    const entityInfoMap = /* @__PURE__ */ new Map();
    for (const [entityType, typeUsages] of usagesByType) {
      const entityIds = typeUsages.map((u) => u.entityId);
      const entityConfig = entityRegistry.get(entityType);
      if (!entityConfig) {
        console.warn(`[PatternUsageService] Unknown entity type: ${entityType}, skipping entity info lookup`);
        entityInfoMap.set(entityType, /* @__PURE__ */ new Map());
        continue;
      }
      const tableName = entityConfig.tableName || entityConfig.slug;
      try {
        const columnsResult = await queryRows(
          `SELECT column_name
           FROM information_schema.columns
           WHERE table_schema = 'public' AND table_name = $1`,
          [tableName]
        );
        const columns = new Set(columnsResult.map((c) => c.column_name));
        const selectParts = ["id"];
        if (columns.has("title")) selectParts.push("title");
        if (columns.has("name")) selectParts.push("name");
        if (columns.has("firstName")) selectParts.push('"firstName"');
        if (columns.has("lastName")) selectParts.push('"lastName"');
        if (columns.has("email")) selectParts.push("email");
        if (columns.has("slug")) selectParts.push("slug");
        if (columns.has("status")) selectParts.push("status");
        if (columns.has("updatedAt")) selectParts.push('"updatedAt"');
        const entities = await queryWithRLS(
          `SELECT ${selectParts.join(", ")} FROM "${tableName}" WHERE id = ANY($1)`,
          [entityIds],
          userId
        );
        const infoMap = /* @__PURE__ */ new Map();
        for (const entity of entities) {
          infoMap.set(entity.id, {
            title: entity.title,
            name: entity.name,
            firstName: entity.firstName,
            lastName: entity.lastName,
            email: entity.email,
            slug: entity.slug,
            status: entity.status,
            updatedAt: entity.updatedAt
          });
        }
        entityInfoMap.set(entityType, infoMap);
      } catch (error) {
        console.error(`[PatternUsageService] Could not fetch entity info for ${entityType}:`, error);
        entityInfoMap.set(entityType, /* @__PURE__ */ new Map());
      }
    }
    return usages.map((usage) => {
      const typeInfo = entityInfoMap.get(usage.entityType);
      const entityInfo = typeInfo == null ? void 0 : typeInfo.get(usage.entityId);
      return {
        ...usage,
        entityTitle: entityInfo == null ? void 0 : entityInfo.title,
        entityName: entityInfo == null ? void 0 : entityInfo.name,
        entityFirstName: entityInfo == null ? void 0 : entityInfo.firstName,
        entityLastName: entityInfo == null ? void 0 : entityInfo.lastName,
        entityEmail: entityInfo == null ? void 0 : entityInfo.email,
        entitySlug: entityInfo == null ? void 0 : entityInfo.slug,
        entityStatus: entityInfo == null ? void 0 : entityInfo.status,
        entityUpdatedAt: entityInfo == null ? void 0 : entityInfo.updatedAt
      };
    });
  }
  /**
   * Get all pattern IDs that have usages
   * Useful for checking if any patterns are in use before bulk operations
   *
   * @param patternIds - Array of pattern IDs to check
   * @param userId - User ID for RLS
   * @returns Array of pattern IDs that have at least one usage
   */
  static async getPatternsWithUsages(patternIds, userId) {
    if (patternIds.length === 0) return [];
    const results = await queryWithRLS(
      `SELECT DISTINCT "patternId" FROM pattern_usages WHERE "patternId" = ANY($1)`,
      [patternIds],
      userId
    );
    return results.map((r) => r.patternId);
  }
  /**
   * Validate which pattern IDs exist in the database
   *
   * Returns only the IDs that exist and are accessible.
   * Used for lazy cleanup - filtering orphaned pattern references on entity save.
   *
   * @param patternIds - Array of pattern IDs to check
   * @param userId - User ID for RLS
   * @returns Set of pattern IDs that exist
   */
  static async getExistingPatternIds(patternIds, userId) {
    if (!patternIds.length) return /* @__PURE__ */ new Set();
    const result = await queryWithRLS(
      `SELECT id FROM patterns WHERE id = ANY($1::text[])`,
      [patternIds],
      userId
    );
    return new Set(result.map((r) => r.id));
  }
}
export {
  PatternUsageService
};
