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

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

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

export interface TextElement {
  text: string;
}

export interface FixtureControl {
  AddElement?: (value: TextElement, index: number) => boolean;
  GetRange?: () => { GetText?: () => string };
  GetTag: () => string;
  RemoveAllElements?: () => boolean;
  SetAlias?: (value: string) => boolean;
  SetAppearance?: (value: string) => void;
  SetColor?: (value: RgbColor) => boolean;
  SetDate?: (value: Date) => boolean;
  SetLock?: (value: string) => boolean;
  SetPlaceholderText?: (value: string) => boolean;
  SetTag?: (value: string) => boolean;
  alias?: string;
  appearance?: string;
  color?: RgbColor;
  dateValue?: Date;
  elements: TextElement[];
  kind: string;
  lock?: string;
  placeholder?: string;
  tag: 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;
}

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

export interface FixtureDocument {
  GetAllContentControls: () => FixtureControl[];
  InsertContent?: (items: Array<FixtureControl | FixtureParagraph>, replaceSelection: boolean) => boolean;
  SetTrackRevisions?: (enabled: boolean) => boolean;
  controls: FixtureControl[];
}

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;
  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 {
  const calls: FixtureCalls = {
    combo: [],
    checkbox: [],
    date: [],
    colors: [],
    inserted: [],
    paragraphTexts: [],
  };

  function makeControl(kind: string, tag = ''): FixtureControl {
    const control: FixtureControl = {
      kind,
      tag,
      elements: [],
      SetTag(value) {
        control.tag = value;
        return true;
      },
      GetTag() {
        return control.tag;
      },
      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;
      },
      RemoveAllElements() {
        control.elements = [];
        return true;
      },
      AddElement(value, index) {
        control.elements.splice(index, 0, value);
        return true;
      },
      GetRange() {
        return {
          GetText: () => control.elements.map((element) => element.text || '').join(''),
        };
      },
    };

    return control;
  }

  const document: FixtureDocument = {
    controls: [],
    GetAllContentControls() {
      return document.controls;
    },
    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;
      }

      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]);
      return makeControl('dropdown');
    },
    CreateCheckBoxContentControl(properties) {
      calls.checkbox.push(properties);
      return makeControl('checkbox');
    },
    CreateDatePickerContentControl(properties) {
      calls.dateProperties = properties;
      return makeControl('date');
    },
    CreateBlockLvlSdt() {
      return makeControl('multiline');
    },
    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;
        },
      };
      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 } });
}
