export interface DropdownOption {
  display: string;
  value: string;
}

export interface InsertSpec {
  alias: string;
  color?: { B: number; G: number; R: number };
  controlType: 'checkbox' | 'date' | 'dropdown' | 'multiline' | 'text';
  dateFormat?: string;
  debug?: boolean;
  defaultChecked: boolean;
  defaultValue: string;
  options: DropdownOption[];
  placeholder: string;
  selectedIndex: number;
  tag: string;
}

export interface TextDefaultSpec {
  tag: string;
  value: string;
}

export interface TextElement {
  text: string;
  textPr?: FixtureTextProperties;
}

export interface FixtureTextProperties {
  bold?: boolean;
  color?: RgbColor;
  fontFamily?: string;
  fontSize?: number;
  italic?: boolean;
  strikeout?: boolean;
  underline?: boolean;
}

export interface FixtureRange {
  GetText?: () => string;
  GetTextPr?: () => FixtureTextProperties;
  SetTextPr?: (value: FixtureTextProperties) => FixtureRange | null;
}

export interface FixtureControl {
  AddText?: (value: string) => boolean;
  AddElement?: (value: TextElement, index: number) => boolean;
  Delete?: (keepContent: boolean) => boolean;
  GetRange?: () => FixtureRange;
  GetAlias?: () => string;
  GetDropdownList?: () => FixtureDropdownList;
  GetInternalId?: () => string;
  GetLock?: () => string;
  GetPlaceholderText?: () => string;
  GetTag: () => string;
  IsBlockLevel?: () => boolean;
  IsCheckBox?: () => boolean;
  IsCheckBoxChecked?: () => boolean;
  IsComboBox?: () => boolean;
  IsDatePicker?: () => boolean;
  IsDropDownList?: () => boolean;
  RemoveAllElements?: () => boolean;
  Select?: () => boolean;
  SetAlias?: (value: string) => boolean;
  SetAppearance?: (value: string) => void;
  SetColor?: (value: RgbColor) => boolean;
  SetDate?: (value: Date) => boolean;
  SetDateFormat?: (value: string) => boolean;
  SetCheckBoxChecked?: (value: boolean) => boolean;
  SetLock?: (value: string) => boolean;
  SetPlaceholderText?: (value: string) => boolean;
  SetTag?: (value: string) => boolean;
  ToJSON?: (includeContent?: boolean) => string;
  alias?: string;
  appearance?: string;
  checked?: boolean;
  color?: RgbColor;
  dateFormat?: string;
  dateValue?: Date;
  elements: TextElement[];
  kind: string;
  lock?: string;
  placeholder?: string;
  options?: DropdownOption[];
  tag: string;
  textPr?: FixtureTextProperties;
}

export interface FixtureDropdownList {
  Add: (display: string, value: string) => boolean;
  Clear: () => boolean;
  GetAllItems: () => Array<{ GetText: () => string; GetValue: () => string }>;
}

export interface FixtureParagraph extends TextElement {
  AddInlineLvlSdt: (value: FixtureControl) => void;
  AddText: (value: string) => void;
  inlineControl: FixtureControl | null;
}

export interface FixtureRun extends TextElement {
  AddText?: (value: string) => boolean;
  GetTextPr?: () => FixtureTextProperties;
  SetTextPr?: (value: FixtureTextProperties) => FixtureTextProperties;
}

export interface RgbColor {
  b: number;
  g: number;
  r: number;
}

export interface FixtureDocument {
  AcceptAllRevisionChanges?: () => boolean;
  Document?: {
    HaveRevisionChanges?: (includeCurrentUser: boolean) => boolean;
    SetTrackRevisions?: (enabled: boolean) => void;
  };
  GetAllContentControls: () => FixtureControl[];
  GetCurrentRun?: () => FixtureRun | null;
  GetRangeBySelect?: () => FixtureRange | null;
  InsertContent?: (items: Array<FixtureControl | FixtureParagraph>, replaceSelection: boolean) => boolean;
  IsTrackRevisions?: () => boolean;
  SetTrackRevisions?: (enabled: boolean) => boolean;
  controls: FixtureControl[];
  currentTextPr?: FixtureTextProperties;
  selectionTextPr?: FixtureTextProperties;
}

export interface FixtureApi {
  CreateBlockLvlSdt?: () => FixtureControl;
  CreateCheckBoxContentControl?: (properties: { checked: boolean; checkedSymbol: number; uncheckedSymbol: number }) => FixtureControl;
  CreateComboBoxContentControl?: (options: DropdownOption[], selectedIndex: number) => FixtureControl;
  CreateDatePickerContentControl?: (properties: { format: string; lang: string }) => FixtureControl;
  CreateInlineLvlSdt?: () => FixtureControl;
  CreateParagraph: () => FixtureParagraph;
  CreateRGBColor?: (r: number, g: number, b: number) => RgbColor;
  CreateRun: () => FixtureRun;
  GetDocument: () => FixtureDocument;
}

export interface FixtureCalls {
  checkbox: Array<{ checked: boolean; checkedSymbol: number; uncheckedSymbol: number }>;
  colors: RgbColor[];
  combo: Array<[DropdownOption[], number]>;
  date: Date[];
  dateProperties?: { format: string; lang: string };
  inserted: Array<{ block: boolean; control: FixtureControl; replaceSelection: boolean }>;
  paragraphTexts: string[];
}

export interface ApiFixture {
  Api: FixtureApi;
  calls: FixtureCalls;
  document: FixtureDocument;
  makeControl: (kind: string, tag?: string) => FixtureControl;
}

export function makeApiFixture(): ApiFixture {
  let selectionIndex = -1;
  const calls: FixtureCalls = {
    combo: [],
    checkbox: [],
    date: [],
    colors: [],
    inserted: [],
    paragraphTexts: [],
  };

  function makeControl(kind: string, tag = ''): FixtureControl {
    const control: FixtureControl = {
      kind,
      tag,
      elements: [],
      options: [],
      AddText(value) {
        control.elements = [{ text: value }];
        return true;
      },
      Select() {
        selectionIndex = document.controls.indexOf(control);
        return selectionIndex >= 0;
      },
      Delete() {
        const index = document.controls.indexOf(control);
        if (index < 0) return false;
        document.controls.splice(index, 1);
        selectionIndex = index;
        return true;
      },
      SetTag(value) {
        control.tag = value;
        return true;
      },
      GetTag() {
        return control.tag;
      },
      GetAlias() {
        return control.alias || '';
      },
      GetInternalId() {
        return `id-${control.tag}`;
      },
      GetLock() {
        return control.lock || 'unlocked';
      },
      GetPlaceholderText() {
        return control.placeholder || '';
      },
      IsBlockLevel() {
        return control.kind === 'multiline';
      },
      IsCheckBox() {
        return control.kind === 'checkbox';
      },
      IsCheckBoxChecked() {
        return Boolean(control.checked);
      },
      IsComboBox() {
        return control.kind === 'dropdown';
      },
      IsDatePicker() {
        return control.kind === 'date';
      },
      IsDropDownList() {
        return false;
      },
      GetDropdownList() {
        return {
          Clear() {
            control.options = [];
            return true;
          },
          Add(display, value) {
            control.options!.push({ display, value });
            return true;
          },
          GetAllItems() {
            return control.options!.map((option) => ({ GetText: () => option.display, GetValue: () => option.value }));
          },
        };
      },
      SetAlias(value) {
        control.alias = value;
        return true;
      },
      SetLock(value) {
        control.lock = value;
        return true;
      },
      SetAppearance(value) {
        control.appearance = value;
      },
      SetColor(value) {
        control.color = value;
        return true;
      },
      SetPlaceholderText(value) {
        control.placeholder = value;
        return true;
      },
      SetDate(value) {
        control.dateValue = value;
        calls.date.push(value);
        return true;
      },
      SetDateFormat(value) {
        control.dateFormat = value;
        return true;
      },
      SetCheckBoxChecked(value) {
        control.checked = value;
        return true;
      },
      RemoveAllElements() {
        control.elements = [];
        control.textPr = undefined;
        return true;
      },
      AddElement(value, index) {
        control.elements.splice(index, 0, value);
        control.textPr = value.textPr;
        return true;
      },
      GetRange() {
        const range: FixtureRange = {
          GetText: () => control.elements.map((element) => element.text || '').join(''),
          GetTextPr: () => control.textPr || {},
          SetTextPr(value) {
            control.textPr = value;
            return range;
          },
        };
        return range;
      },
      ToJSON() {
        return JSON.stringify({ sdtPr: { date: { dateFormat: control.dateFormat } } });
      },
    };

    return control;
  }

  const document: FixtureDocument = {
    controls: [],
    GetAllContentControls() {
      return document.controls;
    },
    GetCurrentRun() {
      if (!document.currentTextPr) return null;
      return {
        GetTextPr: () => document.currentTextPr!,
        text: '',
      };
    },
    GetRangeBySelect() {
      if (!document.selectionTextPr) return null;
      return {
        GetTextPr: () => document.selectionTextPr!,
      };
    },
    InsertContent(items, replaceSelection) {
      const item = items[0];
      const block = Boolean(item && 'kind' in item && item.kind === 'multiline');
      const control = block ? (item as FixtureControl) : (item as FixtureParagraph).inlineControl;

      if (!control) {
        return false;
      }

      if (selectionIndex >= 0) {
        document.controls.splice(selectionIndex, 0, control);
        selectionIndex = -1;
      } else {
        document.controls.push(control);
      }
      calls.inserted.push({ block, replaceSelection, control });
      return true;
    },
  };

  const Api: FixtureApi = {
    GetDocument() {
      return document;
    },
    CreateRGBColor(r, g, b) {
      const color = { r, g, b };
      calls.colors.push(color);
      return color;
    },
    CreateComboBoxContentControl(options, selectedIndex) {
      calls.combo.push([options, selectedIndex]);
      const control = makeControl('dropdown');
      control.options = [...options];
      if (selectedIndex >= 0 && options[selectedIndex]) control.elements = [{ text: options[selectedIndex].display }];
      return control;
    },
    CreateCheckBoxContentControl(properties) {
      calls.checkbox.push(properties);
      const control = makeControl('checkbox');
      control.checked = properties.checked;
      return control;
    },
    CreateDatePickerContentControl(properties) {
      calls.dateProperties = properties;
      const control = makeControl('date');
      control.dateFormat = properties.format;
      return control;
    },
    CreateBlockLvlSdt() {
      return makeControl('multiline');
    },
    CreateInlineLvlSdt() {
      return makeControl('text');
    },
    CreateParagraph() {
      const paragraph: FixtureParagraph = {
        text: '',
        inlineControl: null,
        AddText(value) {
          paragraph.text += value;
          calls.paragraphTexts.push(value);
        },
        AddInlineLvlSdt(value) {
          paragraph.inlineControl = value;
        },
      };
      return paragraph;
    },
    CreateRun() {
      const run: FixtureRun = {
        text: '',
        AddText(value) {
          run.text += value;
          return true;
        },
        GetTextPr: () => run.textPr || {},
        SetTextPr(value) {
          run.textPr = value;
          return value;
        },
      };
      return run;
    },
  };

  return { Api, calls, document, makeControl };
}

export function makeInsertSpec(overrides: Partial<InsertSpec> & Pick<InsertSpec, 'controlType'>): InsertSpec {
  return {
    tag: 'eln.field.result',
    alias: '结果',
    placeholder: '请选择',
    defaultValue: '',
    defaultChecked: false,
    options: [],
    selectedIndex: -1,
    color: { R: 23, G: 109, B: 92 },
    ...overrides,
  };
}

export function installOnlyOfficeGlobals(Api: FixtureApi, scope: Record<string, unknown>): void {
  Object.assign(globalThis, { Api, Asc: { scope } });
}
