/* eslint-disable no-magic-numbers */
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import { StoreType } from '@/redux/store';
import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
import { GLYPHS_STATE_INITIAL_MOCK } from '@/redux/glyphs/glyphs.mock';
import { apiPath } from '@/redux/apiPath';
import { HttpStatusCode } from 'axios';
import { layerImageFixture } from '@/models/fixtures/layerImageFixture';
import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
import {
  LAYER_STATE_DEFAULT_DATA,
  LAYERS_STATE_INITIAL_LAYER_MOCK,
} from '@/redux/layers/layers.mock';
import { MODELS_DATA_MOCK_WITH_MAIN_MAP } from '@/redux/models/models.mock';
import { overlayFixture } from '@/models/fixtures/overlaysFixture';
import { showToast } from '@/utils/showToast';
import { MapEditToolsState } from '@/redux/mapEditTools/mapEditTools.types';
import { MAP_EDIT_TOOLS_STATE_INITIAL_MOCK } from '@/redux/mapEditTools/mapEditTools.mock';
import { MAP_EDIT_ACTIONS } from '@/redux/mapEditTools/mapEditTools.constants';
import { Feature } from 'ol';
import Polygon from 'ol/geom/Polygon';
import { overlayGroupFixture } from '@/models/fixtures/overlayGroupsFixture';
import { LayerImageObjectEditFactoryModal } from './LayerImageObjectEditFactoryModal.component';

const mockedAxiosNewClient = mockNetworkNewAPIResponse();

const glyph = { id: 1, file: 23, filename: 'Glyph1.png' };

jest.mock('../../../../utils/showToast');

const renderComponent = (
  initialMapEditToolsState: MapEditToolsState = MAP_EDIT_TOOLS_STATE_INITIAL_MOCK,
): { store: StoreType } => {
  const { Wrapper, store } = getReduxWrapperWithStore({
    ...INITIAL_STORE_STATE_MOCK,
    glyphs: {
      ...GLYPHS_STATE_INITIAL_MOCK,
      data: [glyph],
    },
    layers: {
      0: {
        ...LAYERS_STATE_INITIAL_LAYER_MOCK,
        data: {
          ...LAYER_STATE_DEFAULT_DATA,
          activeLayers: [1],
        },
      },
    },
    modal: {
      isOpen: true,
      modalTitle: overlayFixture.name,
      modalName: 'edit-overlay',
      editOverlayState: overlayFixture,
      editOverlayGroupState: overlayGroupFixture,
      molArtState: {},
      overviewImagesState: {},
      errorReportState: {},
      layerFactoryState: { id: undefined },
      layerImageObjectFactoryState: {
        x: 1,
        y: 1,
        width: 1,
        height: 1,
      },
      layerTextFactoryState: undefined,
    },
    models: {
      ...MODELS_DATA_MOCK_WITH_MAIN_MAP,
    },
    mapEditTools: initialMapEditToolsState,
  });
  return {
    store,
    ...render(
      <Wrapper>
        <LayerImageObjectEditFactoryModal />
      </Wrapper>,
    ),
  };
};

describe('LayerImageObjectEditFactoryModal - component', () => {
  it('should render LayerImageObjectEditFactoryModal component with initial state', () => {
    renderComponent({
      activeAction: null,
      layerObject: {
        ...layerImageFixture,
        glyph: null,
      },
    });

    expect(screen.getByText(/Glyph:/i)).toBeInTheDocument();
    expect(screen.getByText(/File:/i)).toBeInTheDocument();
    expect(screen.getByText(/Submit/i)).toBeInTheDocument();
    expect(screen.getByText(/No Image/i)).toBeInTheDocument();
  });

  it('should display a list of glyphs in the dropdown', async () => {
    renderComponent({
      activeAction: null,
      layerObject: {
        ...layerImageFixture,
        glyph: null,
      },
    });

    const dropdown = screen.getByTestId('autocomplete');
    if (!dropdown.firstChild) {
      throw new Error('Dropdown does not have a firstChild');
    }
    fireEvent.keyDown(dropdown.firstChild, { key: 'ArrowDown' });
    await waitFor(() => expect(screen.getByText(glyph.filename)).toBeInTheDocument());
    fireEvent.click(screen.getByText(glyph.filename));
  });

  it('should update the selected glyph on dropdown change', async () => {
    renderComponent({
      activeAction: null,
      layerObject: {
        ...layerImageFixture,
        glyph: null,
      },
    });

    const dropdown = screen.getByTestId('autocomplete');
    if (!dropdown.firstChild) {
      throw new Error('Dropdown does not have a firstChild');
    }
    fireEvent.keyDown(dropdown.firstChild, { key: 'ArrowDown' });
    await waitFor(() => expect(screen.getByText(glyph.filename)).toBeInTheDocument());
    fireEvent.click(screen.getByText(glyph.filename));

    await waitFor(() => {
      const imgPreview: HTMLImageElement = screen.getByTestId('layer-image-preview');
      const decodedSrc = decodeURIComponent(imgPreview.src);
      expect(decodedSrc).toContain(`glyphs/${glyph.id}/fileContent`);
    });
  });

  it('should handle form submission correctly', async () => {
    mockedAxiosNewClient
      .onPut(apiPath.updateLayerImageObject(0, 1, 1))
      .reply(HttpStatusCode.Ok, layerImageFixture);
    const geometry = new Polygon([
      [
        [10, 10],
        [10, 10],
      ],
    ]);
    const layerObjectFeature = new Feature({ geometry });
    const glyphData = {
      id: 1,
      x: 1,
      y: 1,
      width: 1,
      height: 1,
      layer: 1,
      glyph: 1,
      z: 1,
    };
    const getGlyphDataMock = jest.fn(() => glyphData);
    jest.spyOn(layerObjectFeature, 'get').mockImplementation(key => {
      if (key === 'updateElement') return (): void => {};
      if (key === 'getObjectData') return getGlyphDataMock;
      return undefined;
    });
    renderComponent({
      activeAction: MAP_EDIT_ACTIONS.TRANSFORM_IMAGE,
      layerObject: glyphData,
    });

    const submitButton = screen.getByText(/Submit/i);

    await act(async () => {
      fireEvent.click(submitButton);
    });

    expect(showToast).toHaveBeenCalledWith({
      message: 'The image has been successfully updated',
      type: 'success',
    });
  });

  it('should display "No Image" when there is no image file', () => {
    const { store } = renderComponent({
      activeAction: null,
      layerObject: {
        ...layerImageFixture,
        glyph: null,
      },
    });

    store.dispatch({
      type: 'glyphs/clearGlyphData',
    });

    expect(screen.getByText(/No Image/i)).toBeInTheDocument();
  });
});