/* eslint-disable @typescript-eslint/naming-convention */
import { describe, it, expect } from 'vitest';
import { AddMethod } from '../../Enums/AddMethod';
import { Orientation } from '../../Enums/Orientation';
import { Position } from '../../Enums/Position';
import { PositionReference } from '../../Enums/PositionReference';
import { IAction } from '../../Interfaces/IAction';
import { IAvailableContainer } from '../../Interfaces/IAvailableContainer';
import { IAvailableSymbol } from '../../Interfaces/IAvailableSymbol';
import { ICategory } from '../../Interfaces/ICategory';
import { IConfiguration } from '../../Interfaces/IConfiguration';
import { IContainerModel, ContainerModel } from '../../Interfaces/IContainerModel';
import { IHistoryState } from '../../Interfaces/IHistoryState';
import { IPattern } from '../../Interfaces/IPattern';
import { DEFAULT_MAINCONTAINER_PROPS, GetDefaultContainerProps } from '../../utils/default';
import { FetchConfiguration } from './api';

const CSHARP_WEB_API_BASE_URL = 'http://localhost:5209/';
const CHARP_WEB_API_RESOURCE_URL = 'SVGLD';
const CSHARP_WEB_API_URL = CSHARP_WEB_API_BASE_URL + CHARP_WEB_API_RESOURCE_URL + '/';

// TODO: Migrate this test to SVGLDWebAPI rather than using test-server/
describe.concurrent('Test server test', () => {
  it('Load environment', () => {
    const url = import.meta.env.VITE_API_FETCH_URL;
    expect(url).toBe('http://localhost:5000');
  });

  it('Fetch configuration', async() => {
    const configuration = await FetchConfiguration();
    expect(configuration.MainContainer).toBeDefined();
    expect(configuration.MainContainer.Height).toBeGreaterThan(0);
    expect(configuration.MainContainer.Width).toBeGreaterThan(0);
    expect(configuration.AvailableContainers.length).toBeGreaterThan(-1);
    expect(configuration.AvailableSymbols.length).toBeGreaterThan(-1);
  });
});

async function Post2API(resource: string, body: string, method = 'POST'): Promise<boolean> {
  return await new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method, CSHARP_WEB_API_URL + resource, true);
    xhr.onreadystatechange = () => { // Call a function when the state changes.
      if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        resolve(xhr.response === 'true');
      }
      if (xhr.status === 400) {
        reject(xhr);
      }
    };
    xhr.onerror = () => {
      reject(xhr);
    };
    xhr.setRequestHeader('Content-type', 'application/json');
    xhr.send(body);
  });
}

/**
 * Serialization tests for type compatibility of csharp classes
 * See csharp/SVGLDWebAPI/README.md
 */
describe.concurrent('Models test suite', () => {
  it('ActionContainerModel', async() => {
    const model: IAction = {
      Id: 'string',
      CustomLogo: {
        Name: 'string',
        Url: 'string',
        Base64Image: 'string',
        Svg: 'string'
      },
      Label: 'string',
      Description: 'string',
      Action: 'string',
      AddingBehavior: 0
    };
    const res = await Post2API('ActionContainerModel', JSON.stringify(model));
    expect(res).toBe(true);
  });

  it('AddingBehaviorEnumModel', async() => {
    let model: AddMethod = AddMethod.Append;
    const res0 = await Post2API('AddingBehaviorEnumModel', JSON.stringify(model));
    model = AddMethod.Insert;
    const res1 = await Post2API('AddingBehaviorEnumModel', JSON.stringify(model));
    model = AddMethod.Replace;
    const res2 = await Post2API('AddingBehaviorEnumModel', JSON.stringify(model));
    model = AddMethod.ReplaceParent;
    const res3 = await Post2API('AddingBehaviorEnumModel', JSON.stringify(model));
    model = 69;
    const res4 = await Post2API('AddingBehaviorEnumModel', JSON.stringify(model));
    expect(res0).toBe(true);
    expect(res1).toBe(true);
    expect(res2).toBe(true);
    expect(res3).toBe(true);
    expect(res4).toBe(true);
  });

  const mainContainer = new ContainerModel(
    DEFAULT_MAINCONTAINER_PROPS
  );

  const containers = new Map<string, IContainerModel>();
  const historyState: IHistoryState = {
    lastAction: 'string',
    mainContainer: mainContainer.properties.id,
    containers,
    selectedContainerId: '3',
    typeCounters: {
      main: 1
    },
    symbols: new Map(),
    selectedSymbolId: ''
  };

  it('ApplicationStateModel', async() => {
    const res = await Post2API('ApplicationStateModel', JSON.stringify(historyState));
    expect(res).toBe(true);
  });

  const availableContainerModel: IAvailableContainer = {
    Type: 'string',
    DisplayedText: 'string',
    Category: 'string',
    Orientation: 0,
    X: 0,
    Y: 0,
    Width: 0,
    Height: 0,
    MinWidth: 0,
    MaxWidth: 0,
    MinHeight: 0,
    MaxHeight: 0,
    Margin: {
      left: 0,
      bottom: 0,
      top: 0,
      right: 0
    },
    IsAnchor: true,
    IsFlex: true,
    Pattern: 'string',
    AddMethod: 0,
    DefaultChildType: 'string',
    PositionReference: 0,
    HideChildrenInTreeview: true,
    ShowSelfDimensions: [
      Position.Down,
      Position.Left,
      Position.Right,
      Position.Up
    ],
    ShowChildrenDimensions: [
      Position.Down,
      Position.Left,
      Position.Right,
      Position.Up
    ],
    MarkPosition: [
      Orientation.Horizontal,
      Orientation.Vertical
    ],
    ShowDimensionWithMarks: [
      Position.Down,
      Position.Left,
      Position.Right,
      Position.Up
    ],
    IsHidden: true,
    Blacklist: [
      'string'
    ],
    Whitelist: [
      'string'
    ],
    Actions: [
      {
        Id: 'string',
        CustomLogo: {
          Name: 'string',
          Url: 'string',
          Base64Image: 'string',
          Svg: 'string'
        },
        Label: 'string',
        Description: 'string',
        Action: 'string',
        AddingBehavior: 0
      }
    ],
    CustomSVG: 'string',
    Style: {},
    UserData: {
      additionalProp1: 'string',
      additionalProp2: 'string',
      additionalProp3: 'string'
    }
  };

  it('AvailableContainerModel', async() => {
    const res = await Post2API('ApplicationStateModel', JSON.stringify(availableContainerModel));
    expect(res).toBe(true);
  });

  const availableSymbolModel: IAvailableSymbol = {
    Name: 'string',
    Image: {
      Name: 'string',
      Url: 'string',
      Base64Image: 'string',
      Svg: 'string'
    },
    PositionReference: PositionReference.BottomCenter,
    Width: 0,
    Height: 0
  };

  it('AvailableSymbolModel', async() => {
    const res = await Post2API('AvailableSymbolModel', JSON.stringify(availableSymbolModel));
    expect(res).toBe(true);
  });

  const category: ICategory = {
    Type: 'string',
    DisplayedText: 'string'
  };

  it('Category', async() => {
    const res = await Post2API('Category', JSON.stringify(category));
    expect(res).toBe(true);
  });

  const pattern: IPattern = {
    children: ['string'],
    id: 'string',
    text: 'string',
    wrapper: 'string'
  };

  it('ConfigurationResponseModel', async() => {
    const model: IConfiguration = {
      AvailableContainers: [
        availableContainerModel
      ],
      AvailableSymbols: [
        availableSymbolModel
      ],
      Categories: [
        category
      ],
      MainContainer: availableContainerModel,
      Patterns: [pattern]
    };

    const res = await Post2API('ConfigurationResponseModel', JSON.stringify(model));
    expect(res).toBe(true);
  });

  const containerProperties = GetDefaultContainerProps(
    'container',
    0,
    null,
    0, 0, 0, 0, availableContainerModel);

  it('ContainerModel', async() => {
    const model: IContainerModel = {
      children: [],
      properties: containerProperties,
      userData: {}
    };
    const res = await Post2API('ContainerModel', JSON.stringify(model));
    expect(res).toBe(true);
  });

  it('ContainerProperties', async() => {
    const res = await Post2API('ContainerModel', JSON.stringify(containerProperties));
    expect(res).toBe(true);
  });

  it('CSSStyle', async() => {
    const model: React.CSSProperties = {
      strokeWidth: '0',
      fillOpacity: '0',
      stroke: 'black',
      fill: 'black'
    };

    const res = await Post2API('CSSStyle', JSON.stringify(model));
    expect(res).toBe(true);
  });
});
