import type { DraftField } from './draft';
import type { FillFieldValue, StepFillStructure } from './types';

import { parseTag } from './tags';

export interface CheckboxGroupViolation {
  checkboxGroupCode: string;
  fields: DraftField[];
  kind: 'invalid' | 'maximum' | 'minimum';
  maxSelected: null | number;
  minSelected: number;
  selectedCount: number;
}

export interface CheckboxGroupTransition {
  accepted: boolean;
  changes: Array<{ tag: string; value: FillFieldValue }>;
  message?: string;
}

export function checkboxGroupRuntimeIdentity(
  field: DraftField,
  structure?: StepFillStructure,
): string | undefined {
  if (field.type !== 'checkbox' || !field.checkboxGroupCode || field.readOnly) return undefined;
  const parsed = parseTag(field.tag);
  if (!parsed || parsed.type === 'reference') return undefined;
  if (parsed.type === 'repeat') {
    return `repeat:${parsed.groupCode}:${parsed.rowId}:${field.checkboxGroupCode}`;
  }
  const stepId = structure ? structure.controlSteps[field.tag] : '';
  return stepId === undefined ? undefined : `step:${stepId}:${field.checkboxGroupCode}`;
}

export function checkboxGroupDeselections(
  fields: DraftField[],
  target: DraftField,
  value: FillFieldValue,
  structure?: StepFillStructure,
): Array<{ tag: string; value: false }> {
  return checkboxGroupTransition(fields, target, value, structure).changes
    .filter((change): change is { tag: string; value: false } => change.tag !== target.tag && change.value === false);
}

export function checkboxGroupTransition(
  fields: DraftField[],
  target: DraftField,
  value: FillFieldValue,
  structure?: StepFillStructure,
): CheckboxGroupTransition {
  const targetChange = { tag: target.tag, value };
  if (target.type !== 'checkbox' || typeof value !== 'boolean') {
    return { accepted: true, changes: [targetChange] };
  }
  const identity = checkboxGroupRuntimeIdentity(target, structure);
  if (!identity || !target.checkboxGroupCode || value === false) {
    return { accepted: true, changes: [targetChange] };
  }
  const members = fields.filter((field) => checkboxGroupRuntimeIdentity(field, structure) === identity);
  const rule = checkboxGroupRule(members);
  if (!rule.valid) {
    return {
      accepted: false,
      changes: [],
      message: `选择组“${target.checkboxGroupCode}”数量规则无效`,
    };
  }
  const selectedPeers = members.filter((field) => field.tag !== target.tag && field.draftValue === true);
  if (rule.maxSelected === 1) {
    return {
      accepted: true,
      changes: [targetChange, ...selectedPeers.map((field) => ({ tag: field.tag, value: false as const }))],
    };
  }
  if (rule.maxSelected !== null && selectedPeers.length + 1 > rule.maxSelected) {
    return {
      accepted: false,
      changes: [],
      message: `选择组“${target.checkboxGroupCode}”最多选择 ${rule.maxSelected} 项`,
    };
  }
  return { accepted: true, changes: [targetChange] };
}

export function checkboxGroupViolations(
  fields: DraftField[],
  structure?: StepFillStructure,
): CheckboxGroupViolation[] {
  const groups = new Map<string, DraftField[]>();
  for (const field of fields) {
    const identity = checkboxGroupRuntimeIdentity(field, structure);
    if (!identity || !field.checkboxGroupCode) continue;
    groups.set(identity, [...(groups.get(identity) ?? []), field]);
  }
  const violations: CheckboxGroupViolation[] = [];
  for (const members of groups.values()) {
    const rule = checkboxGroupRule(members);
    const selected = members.filter((field) => field.draftValue === true);
    const common = {
      checkboxGroupCode: members[0]!.checkboxGroupCode!,
      fields: selected,
      maxSelected: rule.maxSelected,
      minSelected: rule.minSelected,
      selectedCount: selected.length,
    };
    if (!rule.valid) violations.push({ ...common, kind: 'invalid' });
    else if (selected.length < rule.minSelected) violations.push({ ...common, kind: 'minimum' });
    else if (rule.maxSelected !== null && selected.length > rule.maxSelected) {
      violations.push({ ...common, kind: 'maximum' });
    }
  }
  return violations;
}

function checkboxGroupRule(fields: DraftField[]): {
  maxSelected: null | number;
  minSelected: number;
  valid: boolean;
} {
  const first = fields[0];
  const minSelected = first?.checkboxGroupMinSelected ?? 0;
  const maxSelected = first?.checkboxGroupMaxSelected === undefined
    ? 1
    : first.checkboxGroupMaxSelected;
  const validRange = Number.isInteger(minSelected) && minSelected >= 0
    && (maxSelected === null
      || (Number.isInteger(maxSelected) && maxSelected >= 1 && minSelected <= maxSelected));
  const consistent = fields.every((field) =>
    (field.checkboxGroupMinSelected ?? 0) === minSelected
    && (field.checkboxGroupMaxSelected === undefined ? 1 : field.checkboxGroupMaxSelected) === maxSelected);
  return { maxSelected, minSelected, valid: validRange && consistent };
}
