type AnyRecord = Record<string, unknown>;

export interface ApprovalDetail {
  label: string;
  value: string;
}

export interface ApprovalSummaryItem {
  title: string;
  description: string;
  tone?: 'neutral' | 'success' | 'warning' | 'danger' | 'brand';
  details?: ApprovalDetail[];
}

export interface WriteApprovalViewModel {
  goal: string;
  approvalDescription: string;
  modalTitle?: string;
  approveLabel?: string;
  operationCount: number;
  items: ApprovalSummaryItem[];
  checks: ApprovalSummaryItem[];
  rawRequest: unknown;
  technicalDetails?: unknown;
}

const isRecord = (value: unknown): value is AnyRecord => (
  Boolean(value) && typeof value === 'object' && !Array.isArray(value)
);

const asRecord = (value: unknown): AnyRecord => (
  isRecord(value) ? value : {}
);

const asArray = (value: unknown): unknown[] => (
  Array.isArray(value) ? value : []
);

const stringValue = (value: unknown): string | undefined => {
  if (typeof value === 'string' && value.trim()) return value.trim();
  if (typeof value === 'number' || typeof value === 'boolean') return String(value);
  return undefined;
};

const listValue = (value: unknown): string | undefined => {
  if (!Array.isArray(value) || value.length === 0) return undefined;
  return value.map(item => stringValue(item)).filter(Boolean).join(', ') || undefined;
};

const pluralize = (count: number, word: string) => `${count} ${word}${count === 1 ? '' : 's'}`;

const titleCase = (value: string) => (
  value
    .replace(/[._-]+/g, ' ')
    .replace(/\s+/g, ' ')
    .trim()
    .replace(/\b\w/g, char => char.toUpperCase())
);

const compactJson = (value: unknown): string | undefined => {
  if (value === null || value === undefined) return undefined;
  if (typeof value === 'string') return value;
  try {
    const json = JSON.stringify(value);
    return json && json.length > 120 ? `${json.slice(0, 117)}...` : json;
  } catch {
    return String(value);
  }
};

const opName = (op: unknown) => {
  const record = asRecord(op);
  return stringValue(record.op ?? record.action ?? record.type) ?? 'operation';
};

const opArgs = (op: unknown) => asRecord(asRecord(op).args);
const opValues = (op: unknown) => asRecord(asRecord(op).values);

const fieldsFromValues = (values: AnyRecord) => asRecord(values.fields);

const fieldDetails = (fields: AnyRecord): ApprovalDetail[] => (
  Object.keys(fields).slice(0, 8).map(key => ({ label: titleCase(key), value: compactJson(fields[key]) ?? 'set' }))
);

const scopedDetails = (details: (ApprovalDetail | undefined)[]) => details.filter(Boolean) as ApprovalDetail[];

const patchDetails = (values: AnyRecord): ApprovalDetail[] => {
  const directSet = asRecord(values.set);
  const directDelete = asArray(values.delete);
  const fieldSet = asRecord(asRecord(values.fields).set);
  const fieldDelete = asArray(asRecord(values.fields).delete);
  const registeredSet = asRecord(asRecord(values.registered_meta).set);
  const registeredDelete = asArray(asRecord(values.registered_meta).delete);
  const acfSet = asRecord(asRecord(values.acf_fields).set);
  const acfDelete = asArray(asRecord(values.acf_fields).delete);

  return [
    ...Object.keys(directSet).map(key => ({ label: key, value: compactJson(directSet[key]) ?? 'set' })),
    ...directDelete.map(value => ({ label: String(value), value: 'delete' })),
    ...Object.keys(fieldSet).map(key => ({ label: key, value: compactJson(fieldSet[key]) ?? 'set' })),
    ...fieldDelete.map(value => ({ label: String(value), value: 'delete' })),
    ...Object.keys(registeredSet).map(key => ({ label: key, value: compactJson(registeredSet[key]) ?? 'set' })),
    ...registeredDelete.map(value => ({ label: String(value), value: 'delete' })),
    ...Object.keys(acfSet).map(key => ({ label: key, value: compactJson(acfSet[key]) ?? 'set' })),
    ...acfDelete.map(value => ({ label: String(value), value: 'delete' })),
  ].slice(0, 10);
};

const patchChangeCount = (values: AnyRecord) => Math.max(1, patchDetails(values).length);

export const describeSiteWriteOp = (op: unknown): ApprovalSummaryItem => {
  const name = opName(op);
  const args = opArgs(op);
  const values = opValues(op);
  const fields = fieldsFromValues(values);
  const postId = stringValue(args.post_id ?? args.source_post_id);

  if (name === 'rewrite.flush') {
    return {
      title: 'Refresh rewrite rules',
      description: 'Flush WordPress rewrite rules so permalinks and routes are regenerated.',
      tone: 'warning',
    };
  }
  if (name === 'cache.clear') {
    const targets = listValue(asArray(values.targets).length ? values.targets : ['object', 'transients']);
    return {
      title: 'Clear caches',
      description: `Clear ${targets ?? 'selected'} caches.`,
      tone: 'warning',
    };
  }
  if (name === 'maintenance.run') {
    const tasks = listValue(asArray(values.tasks).length ? values.tasks : ['cron']);
    return {
      title: 'Run maintenance',
      description: `Run ${tasks ?? 'selected'} maintenance tasks.`,
      tone: 'warning',
    };
  }
  if (name === 'option.patch') {
    const setCount = Object.keys(asRecord(values.set)).length;
    const deleteCount = asArray(values.delete).length;
    return {
      title: 'Update WordPress settings',
      description: `Change ${pluralize(setCount + deleteCount, 'setting')}.`,
      tone: 'warning',
      details: [
        ...Object.keys(asRecord(values.set)).map(key => ({ label: key, value: compactJson(asRecord(values.set)[key]) ?? 'set' })),
        ...asArray(values.delete).map(value => ({ label: String(value), value: 'delete' })),
      ].slice(0, 10),
    };
  }
  if (name === 'post.clone') {
    return {
      title: 'Create a draft copy',
      description: `Clone ${postId ? `post ${postId}` : 'the selected content'} into a new draft.`,
      tone: 'brand',
      details: fieldDetails(fields),
    };
  }
  if (name === 'post.create') {
    const postType = stringValue(fields.post_type) ?? 'content';
    const status = stringValue(fields.post_status ?? fields.status) ?? 'draft';
    return {
      title: `Create ${postType}`,
      description: `Create a new ${postType} with ${status} status.`,
      tone: status === 'publish' ? 'warning' : 'brand',
      details: fieldDetails(fields),
    };
  }
  if (name === 'post.update') {
    return {
      title: 'Update content settings',
      description: `Update ${postId ? `post ${postId}` : 'the selected content'} settings.`,
      tone: 'brand',
      details: fieldDetails(fields),
    };
  }
  if (name === 'post.publish') {
    return {
      title: 'Publish content',
      description: `Publish ${postId ? `post ${postId}` : 'the selected content'}.`,
      tone: 'warning',
    };
  }
  if (name === 'post.meta_patch') {
    return {
      title: 'Update metadata or custom fields',
      description: `Patch ${pluralize(patchChangeCount(values), 'field')} for ${postId ? `post ${postId}` : 'the selected content'}.`,
      tone: 'brand',
      details: patchDetails(values),
    };
  }
  if (name === 'post_type.create') {
    const postType = stringValue(values.post_type) ?? 'custom post type';
    const label = stringValue(values.plural_label) ?? postType;
    return {
      title: 'Create custom post type',
      description: `Create the ACF-managed ${label} post type.`,
      tone: 'warning',
      details: fieldDetails(values),
    };
  }
  if (name === 'post_type.update') {
    const postType = stringValue(values.post_type) ?? 'custom post type';
    return {
      title: 'Update custom post type',
      description: `Update the ACF-managed ${postType} post type.`,
      tone: 'warning',
      details: fieldDetails(values),
    };
  }
  return {
    title: titleCase(name),
    description: `Run the ${titleCase(name).toLowerCase()} operation.`,
    tone: 'neutral',
  };
};

const CONTENT_WRITE_OPS = new Set([
  'replace_body',
  'replace_block',
  'insert_before',
  'insert_after',
  'delete_block',
  'set_attr',
  'set_attrs',
  'set_attr_path',
  'replace_html_text',
  'replace_html_link',
  'replace_html_media',
  'replace_shortcode',
  'replace_custom_css',
  'delete_custom_css',
]);

const describeContentWriteOp = (op: unknown, args: AnyRecord): ApprovalSummaryItem => {
  const name = opName(op);
  const record = asRecord(op);
  const postId = stringValue(args.post_id);
  const target = postId ? `post ${postId}` : 'the selected content';
  const ref = stringValue(record.ref ?? record.id ?? record.path);
  const baseDetails = scopedDetails([
    postId ? { label: 'Post', value: postId } : undefined,
    stringValue(args.rev) ? { label: 'Revision', value: stringValue(args.rev) as string } : undefined,
    stringValue(args.ws) ? { label: 'Workspace', value: stringValue(args.ws) as string } : undefined,
    ref ? { label: 'Target', value: ref } : undefined,
  ]);

  if (name === 'replace_body') {
    return {
      title: 'Replace body content',
      description: `Replace the full block-editor body for ${target}.`,
      tone: 'warning',
      details: baseDetails,
    };
  }
  if (name === 'replace_custom_css') {
    return {
      title: 'Update page CSS',
      description: `Replace page-level custom CSS for ${target}.`,
      tone: 'warning',
      details: baseDetails,
    };
  }
  if (name === 'delete_custom_css') {
    return {
      title: 'Remove page CSS',
      description: `Remove page-level custom CSS from ${target}.`,
      tone: 'warning',
      details: baseDetails,
    };
  }
  if (name === 'replace_block') {
    return {
      title: 'Replace a block',
      description: `Replace one block in ${target}.`,
      tone: 'brand',
      details: baseDetails,
    };
  }
  if (name === 'insert_before' || name === 'insert_after') {
    return {
      title: name === 'insert_before' ? 'Insert content before a block' : 'Insert content after a block',
      description: `Insert block-editor content in ${target}.`,
      tone: 'brand',
      details: baseDetails,
    };
  }
  if (name === 'delete_block') {
    return {
      title: 'Delete a block',
      description: `Delete one block from ${target}.`,
      tone: 'warning',
      details: baseDetails,
    };
  }
  if (name === 'set_attr' || name === 'set_attrs' || name === 'set_attr_path') {
    return {
      title: 'Update block settings',
      description: `Update saved block attributes in ${target}.`,
      tone: 'brand',
      details: scopedDetails([
        ...baseDetails,
        stringValue(record.key) ? { label: 'Attribute', value: stringValue(record.key) as string } : undefined,
      ]),
    };
  }
  if (name === 'replace_html_text') {
    return {
      title: 'Replace visible text',
      description: `Replace saved HTML text in ${target}.`,
      tone: 'brand',
      details: baseDetails,
    };
  }
  if (name === 'replace_html_link') {
    return {
      title: 'Update a link',
      description: `Update a saved HTML link in ${target}.`,
      tone: 'brand',
      details: baseDetails,
    };
  }
  if (name === 'replace_html_media') {
    return {
      title: 'Update media markup',
      description: `Update saved HTML media markup in ${target}.`,
      tone: 'brand',
      details: baseDetails,
    };
  }
  if (name === 'replace_shortcode') {
    return {
      title: 'Replace a shortcode',
      description: `Replace shortcode content in ${target}.`,
      tone: 'brand',
      details: baseDetails,
    };
  }

  return {
    title: titleCase(name),
    description: `Run the ${titleCase(name).toLowerCase()} content operation on ${target}.`,
    tone: 'neutral',
    details: baseDetails,
  };
};

const fallbackWriteGoal = (items: ApprovalSummaryItem[], emptyFallback: string, multipleFallback: string) => {
  if (items.length === 0) return emptyFallback;
  if (items.length === 1) return items[0].description;
  return multipleFallback;
};

const normalizeChecks = (checks: unknown[]): ApprovalSummaryItem[] => (
  checks.map((check) => {
    const record = asRecord(check);
    const type = stringValue(record.type) ?? 'check';
    const target = stringValue(record.target);
    return {
      title: type === 'http_fetch' ? 'Check page response' : titleCase(type),
      description: target ? `Verify ${target}.` : 'Run a post-action check.',
      tone: 'neutral' as const,
      details: target ? [{ label: 'Target', value: target }] : undefined,
    };
  })
);

const V1_CHECK_DISPLAY_LABEL = 'Verify site change';

const v1CommandExecutionPreview = (command: AnyRecord) => {
  const preview: AnyRecord = {};
  for (const key of ['capability', 'input']) {
    if (command[key] !== undefined) {
      preview[key] = command[key];
    }
  }
  return preview;
};

const v1CommandResultPreview = (result: AnyRecord) => {
  const preview: AnyRecord = {};
  for (const key of ['status', 'data', 'policy', 'error']) {
    if (result[key] !== undefined) {
      preview[key] = result[key];
    }
  }
  return preview;
};

const v1CommandBatchTechnicalDetails = (
  root: AnyRecord,
  commands: AnyRecord[],
  results: AnyRecord[],
) => {
  const approval = asRecord(root.approval);
  const details: AnyRecord = {
    commands: commands.map(v1CommandExecutionPreview),
  };
  if (stringValue(approval.mode) === 'after_execute') {
    details.results_to_share = results.map(v1CommandResultPreview);
  }
  return details;
};

const contentWriteOpFromGrammarChange = (change: unknown): AnyRecord => {
  const record = asRecord(change);
  const path = asArray(record.path).map(stringValue).filter(Boolean);
  if (stringValue(record.op) === 'set' && path.join('.') === 'content.raw') {
    return { op: 'replace_body', markup: record.value };
  }
  return {
    op: stringValue(record.op) ?? 'change',
    path: path.length ? path.join('.') : record.path,
    value: record.value,
  };
};

const contentWriteApprovalArguments = (input: AnyRecord): AnyRecord => {
  if (Array.isArray(input.ops)) return input;
  const target = asRecord(input.target);
  const preconditions = asRecord(target.if);
  const args: AnyRecord = {
    ops: asArray(input.changes).map(contentWriteOpFromGrammarChange),
  };
  const postId = stringValue(target.id);
  const contentHash = stringValue(preconditions.content_hash);
  if (postId) args.post_id = postId;
  if (contentHash) args.rev = contentHash;
  return args;
};

/**
 * Convert a V1 command approval request (approval + grouped Plugin Commands)
 * into the modal view. Summaries are derived from WordPress command display
 * metadata and operation-native command inputs; the technical panel keeps the
 * Plugin command batch shape visible.
 */
export const normalizeV1ApprovalRequestView = (request: unknown): WriteApprovalViewModel => {
  const root = asRecord(request);
  const approval = asRecord(root.approval);
  const display = asRecord(root.display);
  const commands = asArray(root.commands).map(asRecord);
  const results = asArray(root.results).map(asRecord);
  const technicalDetails = v1CommandBatchTechnicalDetails(root, commands, results);
  const resultsByCommandId = new Map(
    results.map(result => [stringValue(result.command_id) ?? '', result])
  );
  const group = stringValue(approval.group) ?? '';

  if (group === 'content_mutation' && commands.length > 0) {
    return {
      ...normalizeWriteApprovalView({
        name: 'content_write',
        arguments: contentWriteApprovalArguments(asRecord(commands[0].input)),
      }),
      rawRequest: root,
      technicalDetails,
    };
  }

  if (group === 'site_mutation') {
    const opCommands = commands.filter(
      command => stringValue(asRecord(command.display).label) !== V1_CHECK_DISPLAY_LABEL
    );
    const checkCommands = commands.filter(
      command => stringValue(asRecord(command.display).label) === V1_CHECK_DISPLAY_LABEL
    );
    // Site command inputs carry id/args/values and the display target carries
    // the operation name used in the approval summary.
    const ops = opCommands.map(command => ({
      op: stringValue(asRecord(command.display).target),
      ...asRecord(command.input),
    }));
    const checks = checkCommands.map(command => {
      const input = asRecord(command.input);
      return { type: input.check_type, target: input.url };
    });
    return {
      ...normalizeWriteApprovalView({
        name: 'site_write',
        arguments: {
          ops,
          checks,
          goal: stringValue(approval.summary) ?? stringValue(display.summary),
        },
      }),
      rawRequest: root,
      technicalDetails,
    };
  }

  // Read approvals (require_read_approval) and unknown groups: render each
  // command's display metadata directly.
  const items: ApprovalSummaryItem[] = commands.map(command => {
    const commandDisplay = asRecord(command.display);
    const target = stringValue(commandDisplay.target);
    const details: ApprovalDetail[] = [];
    const summary = stringValue(commandDisplay.summary);
    if (summary) {
      details.push({ label: 'Summary', value: summary });
    }
    const resultStatus = stringValue(resultsByCommandId.get(stringValue(command.command_id) ?? '')?.status);
    if (resultStatus) {
      details.push({ label: 'Result', value: resultStatus });
    }
    return {
      title: stringValue(commandDisplay.label) ?? stringValue(command.capability) ?? 'Command',
      description: target ? `Target: ${target}` : `Run ${stringValue(command.capability) ?? 'command'}.`,
      tone: 'brand' as const,
      details: details.length > 0 ? details : undefined,
    };
  });
  const isAfterExecuteApproval = stringValue(approval.mode) === 'after_execute';
  return {
    goal: stringValue(approval.action) ?? stringValue(display.label) ?? 'Run operation',
    approvalDescription: isAfterExecuteApproval
      ? 'Approving shares these results with the assistant.'
      : 'Approving runs these operations with your current user permissions.',
    modalTitle: isAfterExecuteApproval ? 'Approve data sharing' : undefined,
    approveLabel: isAfterExecuteApproval ? 'Approve & share' : undefined,
    operationCount: commands.length,
    items,
    checks: [],
    rawRequest: root,
    technicalDetails,
  };
};

export const normalizeWriteApprovalView = (request: unknown): WriteApprovalViewModel => {
  const root = asRecord(request);
  const requestRecord = asRecord(root.request ?? root);
  const args = asRecord(requestRecord.arguments ?? requestRecord);
  const ops = asArray(args.ops ?? args.actions);
  const toolName = stringValue(requestRecord.name ?? root.name);
  const isContentWrite = toolName === 'content_write'
    || (Boolean(args.post_id) && ops.some(op => CONTENT_WRITE_OPS.has(opName(op))));
  const items = isContentWrite ? ops.map(op => describeContentWriteOp(op, args)) : ops.map(describeSiteWriteOp);
  const goal = stringValue(args.goal) ?? fallbackWriteGoal(
    items,
    isContentWrite ? 'update content' : 'run a site operation',
    isContentWrite ? `apply ${pluralize(items.length, 'content change')}` : `run ${pluralize(items.length, 'site operation')}`
  );

  return {
    goal,
    approvalDescription: isContentWrite
      ? 'Approving applies these block-editor content changes to the selected WordPress content.'
      : 'Approving runs these WordPress site operations with your current user permissions.',
    operationCount: ops.length,
    items,
    checks: normalizeChecks(asArray(args.checks)),
    rawRequest: args,
  };
};
