import React, { useContext, useRef, useEffect, forwardRef, useImperativeHandle, useState } from 'react';
import { GridType, PlaylistContextInterface } from '../../contexts/PlaylistContext/PlaylistContext';
import { ConfigContext } from '../../contexts/ConfigContext/ConfigContext';
import { 
  CurrentPlaylistBox, 
  CurrentPlaylistItems, 
  CurrentPlaylistItemsScroll, 
  CurrentPlaylistTopBarBox, 
  SinglePlaylistItemHeader,
  CurrentInfoMainBox,
  CurrentInfoSingleTimeBox,
  CurrentInfoTimeValueSpan,
  StartSpan,
  StopSpan,
  SmallSpan,
} from './CurrentPlaylist.css';
import CurrentPlaylistTopBar from './components/CurrentPlaylistTopBar/CurrentPlaylistTopBar';
import SinglePlaylistItem from './components/SinglePlaylistItem/SinglePlaylistItem';
import {SinglePlaylistCounter, SinglePlaylistName, SinglePlaylistSkipButtonBox, SinglePlaylistTimes} from './components/SinglePlaylistItem/SinglePlaylistItem.css';
import { Timer } from './functions';
import { Toggle } from "react-toggle-component";
import IconButton from '../../elements/IconButton/IconButton';
import { bgColors } from '../../colors';
import { chooseFolder, displayTime, isImage, pathJoin } from '../../utils';

const createCsvWriter = require('csv-writer').createObjectCsvWriter;

interface currentInfoInterface {
  startTime: number, 
  startTimeString: string, 
  endTime: number, 
  endTimeString: string, 
  currentTime: number,
  allPlaylistTime: number;
}

interface TimerInterface {
  pause: () => void, 
  resume: () => void, 
  stop: () => void,
}

const CurrentPlaylist = forwardRef((props: { context: React.Context<PlaylistContextInterface>, secondRef: any, number: number }, ref): JSX.Element => {
  let timer: TimerInterface;
  let inter: NodeJS.Timer;

  // console.log('re-render');

  // #Context
  // Globalny config
  const { config, setConfig } = useContext(ConfigContext);

  // #Context
  // Załadowana playlista
  const { playlist, setPlaylist } = useContext(props.context);

  // Informacje o czasach playlisty
  const [currentInfo, setCurrentInfo] = useState<currentInfoInterface>({
    startTime: null,
    startTimeString: '',
    endTime: null,
    endTimeString: '',
    currentTime: 0,
    allPlaylistTime: 0,
  });

  // Aktywna pozycja na playliście
  const [activeItem, setActiveItem] = useState<number>(-1);

  // Czy playlista jest zapauzowana
  const [isPaused, setIsPaused] = useState<boolean>(false);

  // Aktywny grid
  const [currentGrid, setCurrentGrid] = useState<GridType[]>([]);

  // Zapętlenie playlisty
  const [repeat, setRepeat] = useState<boolean>(true);

  // Automat
  const [isAuto, setIsAuto] = useState(false);

  // Synhronizacja czasu
  const [isTimeSynhro, setIsTimeSynhro] = useState(false);

  // Zaznaczanie/odznaczane wszystkich elementów playlisty
  const [checkedAllItems, setCheckedAllItems] = useState(true);

  // Pokaz/schowaj current info lecącej playlisty
  const [showCurrentInfo, setShowCurrentInfo] = useState(false);

  // Buforuje video - zablukuj przyciski
  // const [isBusy, setIsBusy] = useState(false);

  // Czy aktualnie playlista leci i zlicza czasy
  // const [isPlaying, setIsPlaying] = useState(false);

  // References
  const timerRef = useRef(timer);
  const scrollRef = useRef(null);
  const isPausedRef = useRef(isPaused);
  const isTimeSynhroRef = useRef(isTimeSynhro);
  const isAutoRef = useRef(isAuto);
  const activeItemRef = useRef(activeItem);
  const repeatRef = useRef(repeat);
  const togglerRef = useRef<HTMLInputElement>();
  const currentInfoRef = useRef(currentInfo);

  const setTimerRef = (_timer: TimerInterface) => {
    timerRef.current = _timer;
    timer = _timer;
  }

  const setIsTimeSynhroRef = (_isTimeSynhro: boolean) => {
    isTimeSynhroRef.current = _isTimeSynhro;
    setIsTimeSynhro(_isTimeSynhro);
  }

  const setCurrentInfoRef = (_currentInfo: currentInfoInterface) => {
    currentInfoRef.current = _currentInfo;
    setCurrentInfo(_currentInfo);
  }

  const setRepeatRef = (_repeat: boolean) => {
    repeatRef.current = _repeat;
    setRepeat(_repeat);
  }

  const setActiveItemRef = (_activeItem: number) => {
    activeItemRef.current = _activeItem;
    setActiveItem(_activeItem);
  }

  const setIsAutoRef = (_isAuto: boolean) => {
    setConfig({...config, auto: _isAuto});
    isAutoRef.current = _isAuto;
    setIsAuto(_isAuto);
  }

  const setIsPausedRef = (_isPaused: boolean) => {
    isPausedRef.current = _isPaused;
    setIsPaused(_isPaused);
  }

  // end of References

  const resetCurrentTime = (index: number) => {
    const newPlaylist = [...playlist];
    newPlaylist[index].currentTime = 0;
    setPlaylist(newPlaylist);
  }

  useImperativeHandle(ref, () => ({
    resetPlaylistSettings() {
      setActiveItemRef(-1);
      setIsPausedRef(false);
      stop();
    },
    autostart() {
      setIsAutoRef(true);
      togglerRef.current.checked = true;
      handleStartPlaylistItem(0);
    },
    stopAll(stopVideo = false) {
      clearCurrentInfo();
      stop(stopVideo);
    },
    play() {
      resume();
    }
  }));

  useEffect(() => {
    setIsAutoRef(config.auto);
    togglerRef.current.checked = config.auto;
  },[config.auto]);

  let t1: number | null = null;
  let t2: number | null = null;
  let delay = 0;
  let sumSeconds = 0;

  const l = (s: string) => console.log(s);

  const checkConnection = () => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(false);
      }, 500);
      require('dns').resolve('www.google.com', function(err: any) {
        if (err) {
           resolve(false);
        } else {
           resolve(true);
        }
      });
    });
  };

  const handleStartPlaylistItem = async(playlistId: number) => {
    // l('handleStartPlaylistItem start');
    // setIsBusy(true);
    // let _isBusy = false;

    // for (let row = 0; row < config.rows; row++) {
    //   for (let col = 0; col < config.columns; col++) {
    //     if (window.isBusy[row][col]) {
    //       _isBusy = true;
    //     }
    //     // wait for clear buffer
    //     // await sleep(20);
    //     // const context = window.contextsArray[row][col].canvas.getContext('webgl');
    //     // const color = context.clearColor(0,0,0,0);
    //     // clear canvas
    //     // context.clear(color);
    //   }
    // }

    // if (_isBusy) {
    //   console.log('busy');
    //   handleStartPlaylistItem(playlistId);
    //   return;
    // }

    if (isAutoRef.current) {
      scrollRef.current.scrollTop = playlistId * 28;
    }

    if (timerRef.current) {
      timerRef.current.stop();
    }
    if (t1===null) {
      t1 = performance.now();
    }
    const itemDuration = playlist[playlistId].duration*1000;
    let currectionDuration = itemDuration;
    if (delay>10 && isTimeSynhroRef.current) {
      currectionDuration -= Math.floor(delay);
      delay = 0;
      console.log('## timer  = ' + currectionDuration);
    }

    let tim = new Timer(async function() {
      // while(true) {
      //   if (playlist[activeItemRef.current].currentTime >= playlist[activeItemRef.current].duration) break;
      //   await sleep(10);
      // }
      // if (t1===null) {
    
      if (isTimeSynhroRef.current) {
        sumSeconds += itemDuration;
        delay += (performance.now() - t1) - sumSeconds;
        console.log('## delay = ' + delay);
      }
      // }
      if (playlist[activeItemRef.current].currentTime < playlist[activeItemRef.current].duration) {
        const newPlaylist = [...playlist];
        newPlaylist[activeItemRef.current].currentTime = playlist[activeItemRef.current].duration;
        newPlaylist[activeItemRef.current].sumTime += 1;
        setPlaylist(newPlaylist);
      }

      setCurrentInfoRef({...currentInfoRef.current, currentTime: currentInfoRef.current.currentTime + playlist[activeItemRef.current].currentTime});
      
      if (isAutoRef.current) {
        playNext(activeItemRef.current);
      } else {
        playNext(activeItemRef.current - 1);
      }
    }, currectionDuration);

    setTimerRef(tim);

    // if (inter) {
    //   clearInterval(inter);
    // }

    if (!config.twoPlaylists) {
      props.secondRef.current.stopAll();
    }

    setIsPausedRef(false);
    const item = playlist[playlistId];
    const index = playlistId; // playlist.findIndex( x => x.id === playlistId );

    setCurrentGrid(item.grid);
    setActiveItemRef(index);
    resetCurrentTime(index);


    const iframes = document.getElementById(`videoGrid`).querySelectorAll('webview');
    for (let i = 0; i < iframes.length; i++) {
      iframes[i].parentNode.removeChild(iframes[i]);
    }

    // const divs = document.getElementById(`videoGrid`).querySelectorAll('div.forbet');
    // for (let i = 0; i < divs.length; i++) {
    //   divs[i].parentNode.removeChild(divs[i]);
    // }


    // const oldImages = document.getElementById(`videoGrid`).querySelectorAll('img');
    // for (let i = 0; i < oldImages.length; i++) {
    //   oldImages[i].parentNode.removeChild(oldImages[i]);
    // }


    for (const grid in item.grid) {
      let row = 0;
      const gridNumber = parseInt(grid);
      const col = Math.round(gridNumber%config.columns);
      if (gridNumber >= config.columns) {
        row = Math.round(gridNumber / config.columns);
      }

      // window.gridPlayers[row][col].stop();
      
      // Ustwa na block w razie gdyby lecial wczesniej live i wylaczył komórke na none.
      // document.getElementById(`vc-${row}-${col}`).style.display = 'block';

      // sprawdz czy to nie link czasami
      // jeśli jest to link pusc go w iframie
      // Jeśli to LIVE (URL)

      console.log(item.grid[grid].filePath);

      if (item.grid[grid].filePath.indexOf('http:\/\/') !== -1 || item.grid[grid].filePath.indexOf('https:\/\/') !== -1) {
        window.gridPlayers[row][col].stop();
        console.log('live');
        // document.getElementById(`vc-${row}-${col}`).style.display = 'none';
        const isOnline = true; //await checkConnection();
        console.log('online = ' + isOnline);
        const paths = item.grid[grid].filePath.split('|');

        // #B7D33E
        // const divColor = document.createElement('div');
        // divColor.classList.add('forbet');
        // divColor.style.width = (item.grid[grid].width * config.width) + 'px';
        // divColor.style.height = (config.width) + 'px';
        // document.getElementById(`row-${row}-${col}`).append(divColor);

        // console.log(paths);
        if (isOnline) {
          const iframe = document.createElement('webview') as any;
          iframe.src = paths[1];
          iframe.style.width = (item.grid[grid].width * config.width) + 'px';
          iframe.style.height = (config.width) + 'px';
          document.getElementById(`row-${row}-${col}`).append(iframe);

          let loaded = false;

          // iframe.addEventListener('did-stop-loading', function() {
          //   console.log('loaded');
          //   loaded = true;
          // });

          iframe.addEventListener('did-frame-navigate', function(e: any) {
            if (e.httpResponseCode === 200) {
              console.log('loaded 200');
              loaded = true;
            } else {
              console.log(e);
              console.log('loaded error ' + e.httpResponse);
            }
          })

          // iframe.onload = () => {
          //   loaded = true;
          //   console.log('loaded');
          //   console.log(iframe.contentDocument);
          //   // console.log(iframe.contentWindow);
          // }

          // iframe.onabort = () => console.log('abort');
          // iframe.onerror = () => console.log('error');

          setTimeout(() => {
            console.log(loaded);
            if (!loaded) {
              iframe.remove();
              console.log('nie załadowało liva w 500ms');
              document.getElementById(`vc-${row}-${col}`).style.width = (item.grid[grid].width * config.width) + 'px';
              window.gridPlayers[row][col].play(`file:\/\/\/${pathJoin(paths[0].split('\\'), '\/')}`);
            } else {
              console.log('LIVE OK');
            }
          }, 500)

        } else {
          //const path = paths[0].split('\\');
          //path.splice(-1);
          //path.push('Forbet_1024x56_bt.avi');
          //const pathComplete = path.join('\\');
          //console.log(path);
          // Forbet_1024x56_bt.avi
          //document.getElementById(`vc-${row}-${col}`).style.width = (item.grid[grid].width * config.width) + 'px';
          //window.gridPlayers[row][col].play(`file:\/\/\/${pathJoin(paths[0].split('\\'), '\/')}`);
        }

        // const iframe = document.createElement('iframe');
        // iframe.src = 'file:///C:/liveLED/banner.php.htm';
        // iframe.width = (item.grid[grid].width * config.width) + '';
        // document.getElementById(`row-${row}-${col}`).append(iframe);
        
      } else
      // Jeśli to obrazek
      if(isImage(item.grid[grid].filePath.split('.').pop())) {
        const oldImages = document.getElementById(`row-${row}-${col}`).querySelectorAll('img');
        window.gridPlayers[row][col].stop();
        const htmlImg = document.createElement('img');
        htmlImg.src = item.grid[grid].filePath;
        htmlImg.width = (item.grid[grid].width * config.width);
        document.getElementById(`row-${row}-${col}`).prepend(htmlImg);
        if (oldImages) {
          for (let i = 0; i < oldImages.length; i++) {
            oldImages[i].remove();
          }
        }
      } 
      // Jeśli to film
      else {
        document.getElementById(`vc-${row}-${col}`).style.width = (item.grid[grid].width * config.width) + 'px';
        let deleted = false;
        window.gridPlayers[row][col].onFrameReady = function(frame: any) {

          const oldImages = document.getElementById(`row-${row}-${col}`).querySelectorAll('img');
          if (oldImages && !deleted) {
            for (let i = 0; i < oldImages.length; i++) {
              oldImages[i].remove();
            }
            deleted = true;
          }
          window.contextsArray[row][col].render(frame, frame.width, frame.height, frame.uOffset, frame.vOffset);
        }

        console.log('play video');
        console.log(`file:\/\/\/${pathJoin(item.grid[grid].filePath.split('\\'), '\/')}`);

        window.gridPlayers[row][col].play(`file:\/\/\/${pathJoin(item.grid[grid].filePath.split('\\'), '\/')}`);
        
        // while (true) {
        //   console.log(window.isBusy[row][col]);
        //   if (!window.isBusy[row][col]) {
        //     window.gridPlayers[row][col].play(`file:\/\/\/${pathJoin(item.grid[grid].filePath.split('\\'), '\/')}`);
        //     break;
        //   }
        //   await sleep();
        // }
        // setTimeout(() => {
        //   setIsBusy(false);
        // }, 500);

      }
    }
  }

  // const sleep = (time: number = 100) => {
  //   return new Promise( r => setTimeout(r, time));
  // }

  const pause = () => {
    if (timerRef.current)
      timerRef.current.pause();
    setIsPausedRef(!isPausedRef.current);
    for (const grid in currentGrid) {
      let row = 0;
      const gridNumber = parseInt(grid);
      const col = Math.round(gridNumber%config.columns);
      if (gridNumber >= config.columns) {
        row = Math.round(gridNumber / config.columns);
      }
      window.gridPlayers[row][col].togglePause(); //play(`file:\/\/\/${pathJoin(currentGrid[grid].filePath.split('\\'), '\/')}`);
    }
  }

  // Przycisk Play
  const resume = () => {

    if (isAutoRef.current) {
      setCurrentInfoRef({...currentInfoRef.current, endTime: 0, endTimeString: '', startTime: Date.now(), startTimeString: displayTime(new Date()), allPlaylistTime: playlist.reduce((a, b) => a + (b['duration'] || 0), 0)});
      setIsTimeSynhroRef(true);
      setShowCurrentInfo(true);
    }

    if (currentGrid.length === 0) {
      handleStartPlaylistItem(0);
      return;
    }

    if (isPausedRef.current) {
      if (timerRef.current)
        timerRef.current.resume();
      setIsPausedRef(false);
      for (const grid in currentGrid) {
        let row = 0;
        const gridNumber = parseInt(grid);
        const col = Math.round(gridNumber%config.columns);
        if (gridNumber >= config.columns) {
          row = Math.round(gridNumber / config.columns);
        }

        window.gridPlayers[row][col].togglePause();
      }
    } else {
      if (activeItemRef.current === -1) {
        setActiveItemRef(0);
      }
      handleStartPlaylistItem(activeItemRef.current);
    }
  }

  const playNext = (lastPlayed: number) => {
    if (playlist.length <= lastPlayed + 1) { // Koniec playlisty
      setCurrentInfoRef({...currentInfoRef.current, endTime: Date.now(), endTimeString: displayTime(new Date())});
      if (repeatRef.current) {
        // Ustawiony repeat więc odpalamy playlist od nowa
        handleStartPlaylistItem(0);
        return;
      }
      // Nie mamy repeata playlisty więc ustawiamy na -1
      setActiveItemRef(-1);
      return;
    }
    
    if (!playlist[lastPlayed + 1].play)
      playNext(lastPlayed + 1)
    else
      handleStartPlaylistItem(lastPlayed + 1);
  }

  const handleChangePlayFunction = (index: string) => {
    const foundIndex = playlist.findIndex( x => x.id === index );
    const newPlaylist = [...playlist];
    newPlaylist[foundIndex].play = !newPlaylist[foundIndex].play;
    setPlaylist(newPlaylist);
  }

  const next = () => {
    // setIsBusy(true);
    playNext(activeItemRef.current);
  }

  const prev = () => {
    // setIsBusy(true);
    playNext(activeItemRef.current - 2);
  }

  const clearCurrentInfo = () => {
    setCurrentInfoRef({...currentInfoRef.current,
      startTime: 0, 
      startTimeString: '', 
      endTime: 0, 
      endTimeString: '', 
      currentTime: 0,
    })
  }

  const stop = async(stopVideos = false) => {
    if (timerRef.current)
      timerRef.current.stop();

    if (currentInfoRef.current.startTime)
      setCurrentInfoRef({...currentInfoRef.current, endTime: Date.now(), endTimeString: displayTime(new Date())});

    setActiveItemRef(-1);
    setIsPausedRef(false);
    setIsTimeSynhroRef(false);

    const iframes = document.querySelectorAll('iframe');
    for (var i = 0; i < iframes.length; i++) {
      iframes[i].parentNode.removeChild(iframes[i]);
    }

    if( stopVideos ) {
      for (let row = 0; row < config.rows; row++) {
        for (let col = 0; col < config.columns; col++) {
          window.gridPlayers[row][col].stop();
          // wait for clear buffer
          // await sleep(20);
          // const context = window.contextsArray[row][col].canvas.getContext('webgl');
          // const color = context.clearColor(0,0,0,0);
          // clear canvas
          // context.clear(color);
        }
      }
    }
  }

  const togglePlaylistChecked = () => {
    const newPlaylist = [...playlist];
    const newPlay = !checkedAllItems;
    for (let i = 0; i < newPlaylist.length; i+=1) {
      newPlaylist[i].play = newPlay
    }
    setPlaylist(newPlaylist);
    setCheckedAllItems(newPlay);
  }

  const handleDoReport = async() => {
    let output: {[key: string]: number} = {};
    for (const pItem of playlist) {
      if (pItem.name in output) {
        output[pItem.name] += pItem.sumTime;
      } else {
        output[pItem.name] = pItem.sumTime;
      }
    }
    let outputForCsv: {name: string, time: string}[] = [];

    for (const key in output) {
      outputForCsv.push({name: key, time: new Date(output[key] * 1000).toISOString().substr(11, 8)});
    }

    const csvFile = await chooseFolder();
    const csvWriter = createCsvWriter({
      path: csvFile,
      header: [
        {id: 'name', title: 'Nazwa'},
        {id: 'time', title: 'Czas'}
      ]
    });

    await csvWriter
      .writeRecords(outputForCsv);
  }

  return (
    <CurrentPlaylistBox>
      <CurrentPlaylistTopBarBox>
        <CurrentPlaylistTopBar context={props.context} pause={pause} resume={resume} next={next} prev={prev} stop={stop} active={activeItemRef.current} isAuto={isAutoRef.current} />
        <div>
          <IconButton title="Zapętl playlistę" icon="redo-alt" bgColor='main' onClick={() => setRepeatRef(!repeatRef.current)} customStyle={{background: repeat ? bgColors.main : '#aaa'}} />
          <IconButton title="Pobierz raport" icon="arrow-down" bgColor='second' onClick={handleDoReport} customStyle={{marginLeft: 5}} />
        </div>
        <div>
          Auto <Toggle ref={togglerRef} name="auto-toggle" onToggle={() => setIsAutoRef(!isAutoRef.current)} />
        </div>
      </CurrentPlaylistTopBarBox>
      <CurrentInfoMainBox active={showCurrentInfo}>
        <div style={{flex: '0 1 50px', display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
          <IconButton title="Synhronizacja" icon="clock" disabled={!isTimeSynhroRef.current} bgColor='main' onClick={() => {}} />
          { /* <IconButton title="Reset" icon="sync" bgColor='main' onClick={() => console.log('a')} customStyle={{marginLeft:5}} /> */ }
        </div>
        <div style={{flex: 1, display: 'flex', justifyContent: 'space-evenly', flexDirection:'row'}}>
          <div style={{display: 'flex', flexDirection: 'column', justifyContent: 'space-between', flex: 1}}>
            <CurrentInfoSingleTimeBox>
              <span><StartSpan>START</StartSpan><SmallSpan>/</SmallSpan><StopSpan>KONIEC</StopSpan></span> 
              <CurrentInfoTimeValueSpan>
                <StartSpan>{currentInfo.startTimeString}</StartSpan>
                <SmallSpan>/</SmallSpan>
                <StopSpan>{currentInfo.endTime > 0 
                  ? currentInfo.endTimeString
                  : '?'
                }</StopSpan>
              </CurrentInfoTimeValueSpan>
            </CurrentInfoSingleTimeBox>
            <CurrentInfoSingleTimeBox>
              <SmallSpan>CZAS:</SmallSpan>
              <CurrentInfoTimeValueSpan>
                <SmallSpan>{new Date(currentInfo.allPlaylistTime * 1000).toISOString().substr(11, 8)}</SmallSpan>
              </CurrentInfoTimeValueSpan>
            </CurrentInfoSingleTimeBox>
          </div>
          <div style={{width: 110}}>
            <div style={{fontSize: 16, display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%'}}>
              {new Date(currentInfo.currentTime * 1000).toISOString().substr(11, 8)}
            </div>
          </div>
        </div>
      </CurrentInfoMainBox>
      <SinglePlaylistItemHeader>
        <SinglePlaylistCounter>#</SinglePlaylistCounter>
        <SinglePlaylistName>Nazwa</SinglePlaylistName>
        <SinglePlaylistSkipButtonBox>
          <input type="checkbox" checked={checkedAllItems} onChange={togglePlaylistChecked} />
        </SinglePlaylistSkipButtonBox>
        <div style={{flex: '0 1 100px'}}>
          Czas łączny
        </div>
        <SinglePlaylistTimes>czas</SinglePlaylistTimes>
      </SinglePlaylistItemHeader>
      <CurrentPlaylistItems ref={scrollRef}>
        <CurrentPlaylistItemsScroll>
          {
            playlist.length > 0 &&
              playlist.map((playlistItem, index) => <SinglePlaylistItem context={props.context} key={playlistItem.id} activeItem={activeItemRef.current} playlistItem={playlistItem} index={index} handleChangePlayFunction={handleChangePlayFunction} handleStartPlaylistItem={handleStartPlaylistItem}  />)}
        </CurrentPlaylistItemsScroll>
      </CurrentPlaylistItems>
      {
        playlist.length === 0 &&
          <div style={{display:'flex',width:'100%',height:'100%',justifyContent:'center',alignItems:'center',fontSize:60, color: '#aaa'}}>{props.number}</div>
      }
    </CurrentPlaylistBox>
  )
});

export default CurrentPlaylist;