import type { Part } from "@opencode-ai/sdk/v2";

const GITHUB_ISSUE_CONTEXT_PREFIX = 'GitHub issue context (JSON)';
const GITHUB_PR_CONTEXT_PREFIX = 'GitHub pull request context (JSON)';

export const isSyntheticPart = (part: Part | undefined): boolean => {
    if (!part || typeof part !== "object") {
        return false;
    }
    return Boolean((part as { synthetic?: boolean }).synthetic);
};

/**
 * Checks if a message consists entirely of synthetic parts.
 * Used for status/completion logic (not display filtering).
 */
export const isFullySyntheticMessage = (parts: Part[] | undefined): boolean => {
    if (!Array.isArray(parts) || parts.length === 0) {
        return false;
    }

    return parts.every((part) => isSyntheticPart(part));
};

/**
 * Filters out synthetic parts from a message, but only if there are
 * non-synthetic parts present. If all parts are synthetic, returns
 * them as-is so the message can still be displayed.
 */
export const filterSyntheticParts = (parts: Part[] | undefined): Part[] => {
    if (!Array.isArray(parts) || parts.length === 0) {
        return [];
    }

    const hasNonSynthetic = parts.some((part) => !isSyntheticPart(part));

    const shouldKeepSyntheticPart = (part: Part): boolean => {
        if (!isSyntheticPart(part) || part.type !== 'text') {
            return false;
        }

        const text = (part as { text?: unknown }).text;
        if (typeof text !== 'string') {
            return false;
        }

        const trimmed = text.trimStart();
        return trimmed.startsWith(GITHUB_ISSUE_CONTEXT_PREFIX) || trimmed.startsWith(GITHUB_PR_CONTEXT_PREFIX);
    };

    // If there are non-synthetic parts, filter out synthetic ones
    if (hasNonSynthetic) {
        // Optimization: Check if there are actually any synthetic parts to filter.
        // If not, return the original array to preserve referential equality.
        const hasSynthetic = parts.some((part) => isSyntheticPart(part));
        if (!hasSynthetic) {
            return parts;
        }
        return parts.filter((part) => !isSyntheticPart(part) || shouldKeepSyntheticPart(part));
    }

    // If all parts are synthetic, return them all (so message is displayed)
    return parts;
};
