'use client';

import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import Image from 'next/image';
import Link from 'next/link';

import PlusIcon from '@/svgs/PlusIcon';
import TooltipTriangleIcon from '@/svgs/TooltipTriangleIcon';
import useWindowDimensions from '@/hooks/useWindowDimensions';
import { checkUrlByLanguage } from '@/utils/checkUrlByLanguage';
import { slugify } from '@/utils/slugify';
import { GROUND_FLOOR } from '@/constants';
import { FloorKeyType, PinPositionType, RoomContentType, WindowDimensionsType } from '@/types';
import { Locale, defaultLocale } from '@/i18n.config';

import styles from './Map.module.scss';
import { formatFloor } from '@/utils/formatFloor';
import { padWithLeadingZeros } from '@/utils/padWithLeadingZeros';

export default function Map({
  content = [], floor = GROUND_FLOOR, lang = defaultLocale,
}: {
  content: RoomContentType[]; floor: FloorKeyType; lang: Locale;
}) {
  const windowDimensions = useWindowDimensions() as WindowDimensionsType;

  const controllerRef = useRef<HTMLDivElement | null>(null);
  const mapImageRef = useRef<HTMLImageElement | null>(null);

  const [position, setPosition] = useState<{ x: number, y: number}>({ x: -54, y: 24 });
  const [selectedRoom, setSelectedRoom] = useState<number | null>(null);
  const [zoom, setZoom] = useState<'in' | 'out'>('out');

  const getRelativePosition = useCallback(({ x, y }: PinPositionType) => {
    const { height, width } = windowDimensions;
    const offsetHeight = mapImageRef?.current?.offsetHeight || 0;
    const offsetWidth = mapImageRef?.current?.offsetWidth || 0;

    return ({
      x: ((width || 0) / 2) - ((x / 100) * offsetWidth),
      y: ((height || 0) / 2) - ((y / 100) * (offsetHeight || 0)),
    });
  }, [windowDimensions]);

  useEffect(() => {
    const controller = controllerRef.current;
    let dragging = false;
    let prevPosition = { x: 0, y: 0 };

    const onMouseDown = (event: MouseEvent) => {
      dragging = true;
      prevPosition = { x: event?.clientX, y: event?.clientY };
    };

    const onMouseMove = (event: MouseEvent) => {
      if (!dragging) {
        return;
      }

      const deltaX = event?.clientX - prevPosition.x;
      const deltaY = event?.clientY - prevPosition.y;

      prevPosition = { x: event?.clientX, y: event?.clientY }

      setPosition((position) => {
        const nextX = position.x + deltaX;
        const nextY = position.y + deltaY;

        return ({ x: nextX, y: nextY });
      });
    };

    const onMouseUp = () => { dragging = false; };

    const onTouchstart = (event: TouchEvent) => {
      dragging = true;
      prevPosition = { x: event?.touches?.[0]?.clientX, y: event?.touches?.[0]?.clientY };
    };

    const onTouchMove = (event: TouchEvent) => {
      if (!dragging) {
        return;
      }

      const deltaX = event?.touches?.[0]?.clientX - prevPosition.x;
      const deltaY = event?.touches?.[0]?.clientY - prevPosition.y;

      prevPosition = {
        x: event?.touches?.[0]?.clientX,
        y: event?.touches?.[0]?.clientY,
      };

      setPosition((position) => {
        const nextX = position.x + deltaX;
        const nextY = position.y + deltaY;

        return ({ x: nextX, y: nextY });
      });
    };

    const onTouchend = () => { dragging = false; };

    controller?.addEventListener('mousedown', onMouseDown);
    controller?.addEventListener('mouseup', onMouseUp);
    controller?.addEventListener('mousemove', onMouseMove);
    controller?.addEventListener('touchstart', onTouchstart);
    controller?.addEventListener('touchend', onTouchend);
    controller?.addEventListener('touchmove', onTouchMove);

    return () => {
      controller?.removeEventListener('mousedown', onMouseDown);
      controller?.removeEventListener('mouseup', onMouseUp);
      controller?.removeEventListener('mousemove', onMouseMove);
      controller?.removeEventListener('touchstart', onTouchstart);
      controller?.removeEventListener('touchend', onTouchend);
      controller?.removeEventListener('touchmove', onTouchMove);
    };
  }, [controllerRef, zoom]);

  const onClickZoomIn = () => setZoom('in');

  const onClickZoomOut = () => {
    setPosition({ x: 0, y: 0 });
    setZoom('out');
  };

  const onClickRoom = (id: number, focus: PinPositionType) => {
    if (selectedRoom === id) {
      onClickZoomIn();

      setTimeout(() => setPosition(getRelativePosition(focus)), 25);
    } else {
      setSelectedRoom(id);
    }
  };

  const rooms = useMemo(() => {
    let current: RoomContentType[] = [];

    if (!!content?.length) {
      current = content.filter((c) => c.floor === formatFloor(floor, true));
    }

    return current;
  }, [content, floor]);

  return (
    <div className={styles.Map}>
      <ol className={styles['zoom-controller']}>
        <li>
          <button type="button" disabled={zoom === 'in'} onClick={onClickZoomIn}>+</button>
        </li>
        <li>
          <button type="button" disabled={zoom === 'out'} onClick={onClickZoomOut}>-</button>
        </li>
      </ol>
      <div ref={controllerRef} className={styles['position-controller']} />
      <div
        className={styles['map-container']}
        style={{ transform: `translate(${position.x}px, ${position.y}px)`}}
      >
        <Image
          ref={mapImageRef}
          className={styles[`map-image--${zoom === 'in' ? 'in' : 'out'}`]}
          src={`/images/maps/mapa-museu-jardim-botanico-${floor}.svg`}
          height={1035}
          width={805}
          alt="Mapa"
          draggable={false}
        />
        {zoom === 'out' && !!rooms && (rooms?.map((r: RoomContentType) => (
          <div
            key={r.id}
            className={styles[`room-pin${selectedRoom === r.id ? '--selected' : ''}`]}
            style={{ top: `${r?.position?.y || 0}%`, left: `${r?.position?.x || 0}%` }}
          >
            <span className={styles['pin-label']}>
              {r.name}
              <span className={styles.triangle}>
                <TooltipTriangleIcon />
              </span>
            </span>
            <button type="button" onClick={() => onClickRoom(r.id, r.position)}>
              <PlusIcon />
            </button>
          </div>
        )))}
        {zoom === 'in' && !!rooms && (rooms?.map((r) => {
          let index = 0;
          return (
            <>
              {!!r.sections?.length && r.sections.map((s) => {
                index += 1;

                return (
                  <div
                    key={s.id}
                    className={styles['item-pin']}
                    style={{ top: `${s?.position?.y || 0}%`, left: `${s?.position?.x || 0}%` }}
                  >
                    <Link href={checkUrlByLanguage(lang, `/${floor}/${r.slug}/${slugify(s.title)}`)}>
                      {padWithLeadingZeros(index)}
                    </Link>
                  </div>
                )
              })}
            </>
          );
        }))}
      </div>
    </div>
  );
};
