import { coerceStructuredPayload } from '../structured/coercion.js';
import { tryParseJsonLoose } from '../json/parse-loose.js';
import { looksLikePatch } from '../patch-text/normalize.js';
import { asString, isRecord } from '../validation/shared.js';
import { DEFAULT_APPLY_PATCH_NORMALIZE_ACTIONS } from './default-actions.js';
import { extractNormalizedPatch } from './extract-patch.js';
import { buildPatchFromChangesArray, buildPatchFromStructuredPayload, extractConflictPatchAsStructuredReplace, resolvePathAlias } from './structured-builders.js';
function getActionList(options) {
    if (Array.isArray(options?.actions) && options?.actions.length > 0) {
        return options.actions;
    }
    return DEFAULT_APPLY_PATCH_NORMALIZE_ACTIONS;
}
function runRecordActions(record, state, actions, runNested, isFinalPass) {
    for (const action of actions) {
        if (action.action === 'record_text_fields') {
            for (const field of action.fields) {
                const value = asString(record[field]);
                const extracted = extractNormalizedPatch(value);
                if (extracted.patchText || extracted.failureReason) {
                    return extracted;
                }
            }
            continue;
        }
        if (action.action === 'record_conflict_patch') {
            const patchFieldValue = asString(record[action.patchField]);
            const pathAlias = resolvePathAlias(record, action.fileFields);
            const extracted = extractConflictPatchAsStructuredReplace(pathAlias, patchFieldValue ?? undefined);
            if (extracted.patchText || extracted.failureReason) {
                return extracted;
            }
            continue;
        }
        if (action.action === 'record_raw_envelope') {
            const rawEnvelope = asString(record[action.field]);
            if (!rawEnvelope) {
                continue;
            }
            const fromEnvelope = extractNormalizedPatch(rawEnvelope.trim());
            if (fromEnvelope.patchText || fromEnvelope.failureReason) {
                return fromEnvelope;
            }
            if (action.parseJson === false) {
                continue;
            }
            const maxDepth = typeof action.maxDepth === 'number' ? action.maxDepth : 2;
            if (state.depth >= maxDepth) {
                continue;
            }
            const parsed = tryParseJsonLoose(rawEnvelope.trim());
            if (isRecord(parsed) || Array.isArray(parsed)) {
                const nested = runNested(rawEnvelope.trim(), parsed, state.depth + 1);
                if (nested.patchText || nested.failureReason) {
                    return nested;
                }
            }
            continue;
        }
        if (action.action === 'record_structured_payload') {
            const payload = coerceStructuredPayload(record);
            const extracted = buildPatchFromStructuredPayload(payload);
            if (extracted.patchText || extracted.failureReason) {
                return extracted;
            }
            continue;
        }
        if (action.action === 'invalid_json_guard' && isFinalPass) {
            if (state.looksJsonContainer &&
                isRecord(state.rawArgs) &&
                Object.keys(state.rawArgs).length === 0 &&
                state.rawTrimmed.length > 0 &&
                !looksLikePatch(state.rawTrimmed)) {
                return { failureReason: 'invalid_json' };
            }
        }
    }
    return {};
}
function runActions(state, actions, runNested, isFinalPass) {
    for (const action of actions) {
        if (action.action === 'raw_non_json_patch') {
            if (!state.looksJsonContainer) {
                const extracted = extractNormalizedPatch(state.rawTrimmed);
                if (extracted.patchText || extracted.failureReason) {
                    return extracted;
                }
            }
            continue;
        }
        if (action.action === 'json_container_patch_fallback') {
            if (state.looksJsonContainer && isRecord(state.rawArgs) && Object.keys(state.rawArgs).length === 0) {
                const extracted = extractNormalizedPatch(state.rawTrimmed);
                if (extracted.patchText || extracted.failureReason) {
                    return extracted;
                }
            }
            continue;
        }
        if (action.action === 'array_structured_payload') {
            if (!Array.isArray(state.rawArgs) || state.rawArgs.length === 0) {
                continue;
            }
            const firstRecord = state.rawArgs.find((entry) => isRecord(entry));
            if (firstRecord && Array.isArray(firstRecord.changes)) {
                const extracted = runRecordActions(firstRecord, state, actions, runNested, isFinalPass);
                if (extracted.patchText || extracted.failureReason) {
                    return extracted;
                }
                continue;
            }
            const changesArray = state.rawArgs.filter((entry) => isRecord(entry));
            const extracted = buildPatchFromChangesArray(changesArray);
            if (extracted.patchText || extracted.failureReason) {
                return extracted;
            }
            continue;
        }
        if (action.action === 'raw_string_patch') {
            if (typeof state.rawArgs === 'string') {
                const extracted = extractNormalizedPatch(state.rawArgs);
                if (extracted.patchText || extracted.failureReason) {
                    return extracted;
                }
            }
            continue;
        }
        if (isRecord(state.rawArgs)) {
            const extracted = runRecordActions(state.rawArgs, state, [action], runNested, isFinalPass);
            if (extracted.patchText || extracted.failureReason) {
                return extracted;
            }
        }
    }
    return {};
}
function normalizeState(argsString, rawArgs, depth) {
    const rawTrimmed = typeof argsString === 'string' ? argsString.trim() : '';
    return {
        argsString,
        rawArgs,
        rawTrimmed,
        looksJsonContainer: rawTrimmed.startsWith('{') || rawTrimmed.startsWith('['),
        depth
    };
}
function resolveExtraction(argsString, rawArgs, actions, depth, isFinalPass) {
    const state = normalizeState(argsString, rawArgs, depth);
    const runNested = (nextArgsString, nextRawArgs, nextDepth) => {
        return resolveExtraction(nextArgsString, nextRawArgs, actions, nextDepth, false);
    };
    return runActions(state, actions, runNested, isFinalPass);
}
export function normalizeApplyPatchArgs(argsString, rawArgs, options) {
    const actions = getActionList(options);
    const extracted = resolveExtraction(argsString, rawArgs, actions, 0, true);
    if (extracted.patchText) {
        return { ok: true, patchText: extracted.patchText };
    }
    if (extracted.failureReason) {
        return { ok: false, reason: extracted.failureReason };
    }
    return { ok: false, reason: 'missing_changes' };
}
