import React from 'react';
import {
  HashRouter as Router,
  Switch,
  Route,
  useParams
} from "react-router-dom";
import Random from './rand';
import './App.css';

type Config = {
  sleepTimeSeconds: number;
  showUI: boolean;

}

let CONFIG: Config;
if (process.env.NODE_ENV === 'production') {
  CONFIG = {
    sleepTimeSeconds: 5 * 60,
    showUI: false,
  }
} else {
  CONFIG = {
    sleepTimeSeconds: 10,
    showUI: true,
  }
}

const IMAGE_CHUNK = 256;
const roundup = (v: number, mod: number) => {
  let r = v % mod;
  if (r === 0) {
    return v;
  } else {
    return v + (mod - r);
  }
};

/**
 * Shuffles array in place. ES6 version
 * From https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array
 * @param {Array} a items An array containing the items.
 */
function shuffle(a: Array<MediaItem>) {
  let rng = new Random(new Date().getDay());
    for (let i = a.length - 1; i > 0; i--) {
        const j = Math.floor(rng.nextFloat() * (i + 1));
        [a[i], a[j]] = [a[j], a[i]];
    }
    return a;
}

type MediaMetadata = {
  width: number;
  height: number;
};
type MediaItem = {
  id: string;
  mediaMetadata: MediaMetadata;
  filename: string;
};
type AlbumProps = {
  album: string;
  showUI: boolean;
  sleepTimeSeconds: number;
};
type AlbumState = {
  error: any;
  mediaItems: Array<MediaItem> | null;
  idx: number;
  showUI: boolean;
  timerID: any | null;
};
class Album extends React.Component<AlbumProps, AlbumState> {
  state: AlbumState = {
    error: null,
    mediaItems: null,
    idx: 0,
    showUI: this.props.showUI,
    timerID: null,
  };
  componentDidMount() {
    this.loadAlbum()
  }
  loadAlbum() {
    let {album} = this.props;
    fetch(process.env.PUBLIC_URL + `/api/album/${album}`)
      .then(res => res.json())
      .then(
        (result) => {
          this.setState({mediaItems: result});
          let {sleepTimeSeconds} = this.props;
          let timerID = setInterval(()=>{
            let {idx} = this.state;
            this.setState({idx: idx+1})
            console.log('timer fired');
          }, sleepTimeSeconds*1000);
          this.setState({timerID});
        },
        (error) => this.setState({error}),
      );
  }
  componentWillUnmount() {
    let {timerID} = this.state;
    clearInterval(timerID);
  }
  nextPhoto() {
  }
  render() {
    // TODO(wathiede): fade transition.
    // TODO(wathiede): pair-up portrait orientation images.
    let w = window.innerWidth * window.devicePixelRatio;
    let h = window.innerHeight * window.devicePixelRatio;
    let ratio = w/h;
    if (ratio > 1) {
      // Landscape image
      w = roundup(w, IMAGE_CHUNK);
      h = Math.round(w/ratio);
    } else {
      // Portrait image
      h = roundup(h, IMAGE_CHUNK);
      w = Math.round(h/ratio);
    }
    console.log(`Window size ${window.innerWidth}x${window.innerHeight} with a devicePixelRatio of ${window.devicePixelRatio} for a total size of ${w}x${h}`);

    //let w = roundup(window.innerWidth*window.devicePixelRatio, IMAGE_CHUNK);
    //let h = roundup(window.innerHeight*window.devicePixelRatio, IMAGE_CHUNK);
    let {idx, error, mediaItems, showUI} = this.state;
    if (error !== null) {
      return <h2>Error: {JSON.stringify(error)}</h2>;
    } else if (mediaItems !== null) {
      let landscapes = mediaItems.filter((mi) => {
        let md = mi.mediaMetadata;
        let ratio = md.width/md.height;
        return ratio > 1;
      });

      let portraits = mediaItems.filter((mi) => {
        let md = mi.mediaMetadata;
        let ratio = md.width/md.height;
        return ratio <= 1;
      });

      console.log(`${landscapes.length} landscape photos`);
      console.log(`${portraits.length} portraits photos`);
      let photos;
      if (ratio > 1) {
        console.log('display in landscape mode');
        photos = landscapes;
      } else {
        console.log('display in portrait mode');
        photos = portraits;
      }
      photos = shuffle(photos);

      let numImages = photos.length;
      idx = idx % numImages;
      let nextIdx = (idx+1)%numImages;
      let prevIdx = (numImages+idx-1)%numImages;
      let image = photos[idx];
      let nextImage = photos[nextIdx];
      let prevImage = photos[prevIdx];
      let style: React.CSSProperties = {
        height: '100%',
        width: '100%',
        backgroundColor: 'black',
        backgroundImage: `url(/api/image/${image.id}?w=${w}&h=${h})`,
        backgroundRepeat: 'no-repeat',
        backgroundPosition: 'center center',
        backgroundSize: 'cover',
      };
      let prefetchStyle: React.CSSProperties = {
        backgroundColor: 'rgba(127, 127, 127, 0.5)',
        backgroundPosition: 'center center',
        backgroundRepeat: 'no-repeat',
        backgroundSize: 'cover',
        bottom: 0,
        height: '25%',
        position: 'absolute',
        width: '25%',
      };
      let leftPrefetchStyle: React.CSSProperties = {
        left: 0,
        backgroundImage: `url(/api/image/${prevImage.id}?w=${w}&h=${h})`,
        ...prefetchStyle
      };
      let rightPrefetchStyle: React.CSSProperties = {
        right: 0,
        backgroundImage: `url(/api/image/${nextImage.id}?w=${w}&h=${h})`,
        ...prefetchStyle
      };
      let ui;
      if (showUI) {
        ui = <div id="ui">
          <div
          style={leftPrefetchStyle}
          onClick={(e)=>{
            e.stopPropagation();
            this.setState({idx: prevIdx})
          }}></div>
          <div className="meta">{image.filename}</div>
          <div
          style={rightPrefetchStyle}
          onClick={(e)=>{
            e.stopPropagation();
            this.setState({idx: nextIdx})
          }}></div>
        </div>;
      }
      return <div style={style} onClick={(e)=>{
        e.stopPropagation();
        this.setState({showUI: !showUI})
      }}>
        { ui }
        </div>;
    } else {
      return <h2>Loading...</h2>;
    }
  }
}

type AlbumIndexProps = {
};
type AlbumIndexState = {
  error: any | null,
  albums: Array<any> | null,
};
class AlbumIndex extends React.Component<AlbumIndexProps, AlbumIndexState> {
  state: AlbumIndexState = {
    error: null,
    albums: null,
  }
  componentDidMount() {
    fetch(process.env.PUBLIC_URL + "/api/albums")
      .then(res => res.json())
      .then(
        (result) =>  this.setState({albums: result}),
        (error) => this.setState({error}),
      );
  }
  render() {
    let {error, albums} = this.state;
    if (error !== null) {
      return <h2>Error: {JSON.stringify(error)}</h2>;
    } else if (albums !== null) {
      return albums.map((a) => {
        let img = <img src="https://via.placeholder.com/256x128" className="mr-3" alt="unset"/>;
        if (a.coverPhotoMediaItemId !== undefined) {
          img = <img src={ `/api/image/${a.coverPhotoMediaItemId}?w=256&h=256` } className="mr-3" alt={ a.title }/>
        }

        let figure = <figure key={ a.id } className="figure">
          {img}
          <figcaption className="figure-caption">{ a.title || "No title" } - { a.mediaItemsCount || 0 } photos </figcaption>
        </figure>;
        return <a key={ a.id } href={ '#' + a.id }>
            { figure }
          </a>
      });
    } else {
      return <h2>Loading...</h2>;
    }
  }
}

type AlbumRouteProps = { sleepTimeSeconds: number, showUI: boolean };
const AlbumRoute = ({sleepTimeSeconds, showUI}: AlbumRouteProps) => {
  // We can use the `useParams` hook here to access
  // the dynamic pieces of the URL.
  let { albumId } = useParams();
  albumId = albumId || '';
  return <Album album={albumId} showUI={showUI} sleepTimeSeconds={sleepTimeSeconds} />;
}

const App = () => {
  let {showUI, sleepTimeSeconds} = CONFIG;
  return <Router>
      <Switch>
        <Route exact path="/">
          <div className="container">
            <AlbumIndex />
          </div>
        </Route>
        <Route exact path="/:albumId">
          <AlbumRoute showUI={showUI} sleepTimeSeconds={sleepTimeSeconds} />
        </Route>
      </Switch>
    </Router>
}

export default App;
