import { grpc } from '@improbable-eng/grpc-web';
// import {
//   MediaSet as MediaSetPb,
//   GetRequest,
//   GetAudioRequest,
//   GetAudioProgress,
// } from './generated/media_set_pb';
import {
  MediaSet,
  GrpcWebImpl,
  MediaSetServiceClientImpl,
} from './generated/media_set';

import { useState, useEffect } from 'react';
import { VideoPreview } from './VideoPreview';
import { Overview } from './Overview';
import { Waveform } from './Waveform';
import { ControlBar } from './ControlBar';
import { SeekBar } from './SeekBar';
import './App.css';
import { Duration } from './generated/google/protobuf/duration';

// ported from backend, where should they live?
const thumbnailWidth = 177;
const thumbnailHeight = 100;

// Frames represents a selection of audio frames.
export interface Frames {
  start: number;
  end: number;
}

function App(): JSX.Element {
  const [mediaSet, setMediaSet] = useState<MediaSet | null>(null);
  const [video, _setVideo] = useState(document.createElement('video'));
  const [position, setPosition] = useState(0);
  const [viewport, setViewport] = useState({ start: 0, end: 0 });

  // effects

  // TODO: error handling
  const videoID = new URLSearchParams(window.location.search).get('video_id');
  if (videoID == null) {
    return <></>;
  }

  // fetch mediaset on page load:
  useEffect(() => {
    (async function () {
      const rpc = newRPC();
      const service = new MediaSetServiceClientImpl(rpc);
      const mediaSet = await service.Get({ youtubeId: videoID });

      console.log('got media set:', mediaSet);

      setMediaSet(mediaSet);

      //       const handleProgress = (progress: GetAudioProgress) => {
      //         console.log('got progress', progress);
      //       };

      //       const audioRequest = new GetAudioRequest();
      //       audioRequest.setId(videoID);
      //       audioRequest.setNumBins(1000);
      //       GetMediaSetAudio(grpcHost, audioRequest, handleProgress);

      // console.log('fetching media...');
      // const resp = await fetch(
      //   `http://localhost:8888/api/media_sets/${videoID}`
      // );
      // const respBody = await resp.json();
      // if (respBody.error) {
      //   console.log('error fetching media set:', respBody.error);
      //   return;
      // }
      // const mediaSet = {
      //   id: respBody.id,
      //   source: respBody.source,
      //   audio: {
      //     sampleRate: respBody.audio.sample_rate,
      //     bytes: respBody.audio.bytes,
      //     frames: respBody.audio.frames,
      //     channels: respBody.audio.channels,
      //   },
      //   video: {
      //     bytes: respBody.video.bytes,
      //     thumbnailWidth: respBody.video.thumbnail_width,
      //     thumbnailHeight: respBody.video.thumbnail_height,
      //     durationMillis: Math.floor(respBody.video.duration / 1000 / 1000),
      //   },
      // };
      // setMediaSet(mediaSet);
    })();
  }, []);

  // setup player on first page load only:
  useEffect(() => {
    setInterval(() => {
      setPosition(video.currentTime);
    }, 100);
  }, []);

  // load video when MediaSet is loaded:
  useEffect(() => {
    if (mediaSet == null) {
      return;
    }

    return;

    video.src = `http://localhost:8888/api/media_sets/${videoID}/video`;
    video.muted = false;
    video.volume = 1;
    console.log('set video src', video.src);
  }, [mediaSet]);

  // set viewport when MediaSet is loaded:
  useEffect(() => {
    if (mediaSet == null) {
      return;
    }

    setViewport({ start: 0, end: mediaSet.audioFrames });
  }, [mediaSet]);

  useEffect(() => {
    console.debug('viewport updated', viewport);
  }, [viewport]);

  // handlers

  const handleOverviewSelectionChange = (selection: Frames) => {
    console.log('in handleOverviewSelectionChange', selection);
    if (mediaSet == null) {
      return;
    }

    if (selection.start >= selection.end) {
      setViewport({ start: 0, end: mediaSet.audioFrames });
      return;
    }

    setViewport({ ...selection });
  };

  // render component

  const containerStyles = {
    border: '1px solid black',
    width: '90%',
    margin: '1em auto',
    minHeight: '500px',
    height: '700px',
    display: 'flex',
    flexDirection: 'column',
  } as React.CSSProperties;

  const offsetPixels = Math.floor(thumbnailWidth / 2);

  if (mediaSet == null) {
    // TODO: improve
    return <></>;
  }

  return (
    <>
      <div className="App">
        <div style={containerStyles}>
          <ControlBar
            onPlay={() => {
              video.play();
            }}
            onPause={() => {
              video.pause();
            }}
          />

          <Overview
            mediaSet={mediaSet}
            offsetPixels={offsetPixels}
            height={80}
            position={position}
            onSelectionStart={(x1: number) => {
              console.log('onSelectionStart', x1);
            }}
            onSelectionChange={handleOverviewSelectionChange}
          />

          <Waveform
            mediaSet={mediaSet}
            position={position}
            viewport={viewport}
            offsetPixels={offsetPixels}
          />

          <SeekBar
            position={video.currentTime}
            duration={mediaSet.audioFrames / mediaSet.audioSampleRate}
            offsetPixels={offsetPixels}
            onPositionChanged={(position: number) => {
              video.currentTime = position;
            }}
          />

          <VideoPreview
            video={video}
            position={position}
            duration={millisFromDuration(mediaSet.videoDuration)}
            height={thumbnailHeight}
          />
        </div>
      </div>
    </>
  );
}

export default App;

function millisFromDuration(dur?: Duration): number {
  if (dur == undefined) {
    return 0;
  }
  return Math.floor(dur.seconds * 1000.0 + dur.nanos / 1000.0 / 1000.0);
}

const grpcHost = 'http://localhost:8888';

export function newRPC(): GrpcWebImpl {
  return new GrpcWebImpl(grpcHost, {});
}
