import type { DraftField } from '../domain/draft';
import type { FieldConflict } from '../domain/conflict';
import type { FieldApplyResult, FillFieldValue, RepeatGroup, StepFillStructure } from '../domain/types';

import { defineStore } from 'pinia';

import { checkboxGroupTransition, checkboxGroupViolations } from '../domain/checkbox-group';
import { isReferenceTag } from '../domain/draft';
import { reconcileDocumentValue } from '../domain/conflict';
import { parseTag } from '../domain/tags';

function syncReferenceDrafts(fields: DraftField[], primaryTag: string, value: FillFieldValue) {
  const primary = parseTag(primaryTag);
  if (primary?.type !== 'single') return;
  const prefix = `eln.ref.${primary.fieldCode}.`;
  fields.filter((item) => item.tag.startsWith(prefix)).forEach((item) => {
    item.draftValue = value;
  });
}

export const useFillerStore = defineStore('filler', {
  state: () => ({
    status: 'initializing' as 'error' | 'initializing' | 'ready' | 'working',
    conflicts: {} as Record<string, FieldConflict>,
    checkboxGroupError: '',
    checkboxGroupNotice: '',
    fields: [] as DraftField[],
    fieldErrors: {} as Record<string, string>,
    formulaResultsStale: false,
    focusedTag: null as null | string,
    documentSyncError: '',
    repeatError: '',
    sourceSyncError: '',
    repeatGroups: [] as RepeatGroup[],
    stepStructure: undefined as StepFillStructure | undefined,
    currentStepId: null as null | string,
    message: '正在连接文档...',
  }),
  actions: {
    setStepStructure(structure?: StepFillStructure) {
      this.stepStructure = structure;
      const steps = [...(structure?.configuration.steps ?? [])].sort((left, right) => left.order - right.order);
      this.currentStepId = steps.some((step) => step.id === this.currentStepId)
        ? this.currentStepId
        : (steps[0]?.id ?? null);
    },
    selectStep(stepId: string) {
      if (this.stepStructure?.configuration.steps.some((step) => step.id === stepId)) {
        this.currentStepId = stepId;
      }
    },
    refreshCheckboxGroupError() {
      const violation = checkboxGroupViolations(this.fields, this.stepStructure)[0];
      if (!violation) this.checkboxGroupError = '';
      else if (violation.kind === 'invalid') {
        this.checkboxGroupError = `选择组“${violation.checkboxGroupCode}”数量规则无效`;
      } else if (violation.kind === 'minimum') {
        this.checkboxGroupError = `选择组“${violation.checkboxGroupCode}”至少选择 ${violation.minSelected} 项`;
      } else {
        this.checkboxGroupError = `选择组“${violation.checkboxGroupCode}”最多选择 ${violation.maxSelected} 项`;
      }
    },
    setDraft(tag: string, value: FillFieldValue) {
      if (isReferenceTag(tag)) return false;
      const field = this.fields.find((item) => item.tag === tag);
      if (!field || field.readOnly) return false;
      const transition = checkboxGroupTransition(this.fields, field, value, this.stepStructure);
      if (!transition.accepted) {
        this.checkboxGroupNotice = transition.message ?? '';
        return false;
      }
      this.checkboxGroupNotice = '';
      const changes = transition.changes;
      for (const change of changes) {
        const changedField = this.fields.find((item) => item.tag === change.tag);
        if (!changedField || changedField.readOnly || isReferenceTag(change.tag)) continue;
        if (changedField.draftValue !== change.value) this.formulaResultsStale = true;
        changedField.draftValue = change.value;
        const conflict = this.conflicts[change.tag];
        if (conflict) {
          const reconciliation = reconcileDocumentValue(conflict.baseValue, change.value, conflict.documentValue);
          if (reconciliation.conflict) this.conflicts[change.tag] = reconciliation.conflict;
          else delete this.conflicts[change.tag];
        }
        syncReferenceDrafts(this.fields, change.tag, change.value);
      }
      this.refreshCheckboxGroupError();
      return true;
    },
    syncDocumentField(tag: string, value: FillFieldValue) {
      const field = this.fields.find((item) => item.tag === tag);
      if (!field || (field.type === 'checkbox') !== (typeof value === 'boolean')) return;
      if (field.documentValue !== value) this.formulaResultsStale = true;
      if (isReferenceTag(tag)) {
        field.currentValue = value;
        field.documentValue = value;
        delete this.conflicts[tag];
        return;
      }
      const baseValue = this.conflicts[tag]?.baseValue ?? field.documentValue;
      const reconciliation = reconcileDocumentValue(baseValue, field.draftValue, value);
      field.currentValue = value;
      field.documentValue = reconciliation.documentValue;
      field.draftValue = reconciliation.draftValue;
      if (reconciliation.conflict) this.conflicts[tag] = reconciliation.conflict;
      else delete this.conflicts[tag];
      if (!reconciliation.conflict) syncReferenceDrafts(this.fields, tag, reconciliation.draftValue);
      this.refreshCheckboxGroupError();
    },
    resolveConflict(tag: string, resolution: 'document' | 'draft') {
      const field = this.fields.find((item) => item.tag === tag);
      const conflict = this.conflicts[tag];
      if (!field || !conflict) return;
      if (resolution === 'document') {
        field.draftValue = conflict.documentValue;
        syncReferenceDrafts(this.fields, tag, conflict.documentValue);
      }
      field.documentValue = conflict.documentValue;
      delete this.conflicts[tag];
      this.refreshCheckboxGroupError();
    },
    applyResults(results: FieldApplyResult[], options: { preserveExistingErrors?: boolean } = {}) {
      if (!options.preserveExistingErrors) this.fieldErrors = {};
      for (const result of results) {
        const field = this.fields.find((item) => item.tag === result.tag);
        if (!field) continue;
        delete this.fieldErrors[result.tag];
        if (result.ok) field.documentValue = field.draftValue;
        else this.fieldErrors[result.tag] = result.error || '应用失败';
      }
    },
  },
});
