import { PhotoListPhoto } from "../Structs/PhotoListElements/PhotoListPhoto";
import { PhotoListText } from "../Structs/PhotoListElements/PhotoListText";
import { PhotoListElementType } from "../Structs/PhotoListElementType";
import { PhotoListRow } from "../Structs/PhotoListRow";

const MONTHS = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];

let multilayerIcon = new Image();
multilayerIcon.src = '/icon/layer-group-solid-full.svg';

export class PhotoListRenderingManager{
  private _layout: PhotoListRow[] = [];
  private _canvas!: HTMLCanvasElement;

  private _isLoading = false;

  constructor(){}

  public SetCanvas( canvas: HTMLCanvasElement ){
    this._canvas = canvas;
  }

  public ComputeLayout(){
    this._layout = [];

    let lastDateString = null;
    let row = new PhotoListRow();
    row.Height = 0;

    for (let i = 0; i < window.PhotoManager.FilteredPhotos.length; i++) {
      let photo = window.PhotoManager.FilteredPhotos[i];

      // If date string has changed since the last photo, we should label the correct date above it
      if(lastDateString !== photo.dateString){
        this._layout.push(row);
        row = new PhotoListRow();

        row.Height = 50;

        let dateParts = photo.dateString.split('-');
        lastDateString = photo.dateString;

        row.Elements = [ new PhotoListText(dateParts[2] + ' ' + MONTHS[parseInt(dateParts[1]) - 1] + ' ' + dateParts[0]) ];

        this._layout.push(row);
        row = new PhotoListRow();
      }

      // Check if the current row width plus another photo is too big to fit, push this row to the
      // layout and add the photo to the next row instead
      if(row.Width + photo.scaledWidth! + 10 > this._canvas.width - 100){
        this._layout.push(row);
        row = new PhotoListRow();
      }

      // We should now add this photo to the current row
      row.Elements.push(new PhotoListPhoto(photo));
      row.Width += photo.scaledWidth! + 10;
    }

    this._layout.push(row);
  }

  public Render( ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, scroll: number ){
    let currentY = 0;
    
    // Loop through each row
    for (let i = 0; i < this._layout.length; i++) {
      let row = this._layout[i];

      // Cull rows that are out of frame
      if(currentY - scroll > canvas.height){
        // Reset frames for out of frame rows so they fade back in
        row.Elements.forEach(el => {
          if(el.Type === PhotoListElementType.PHOTO){
            (el as PhotoListPhoto).Photo.frames = 0;
            (el as PhotoListPhoto).Photo.shown = false;
          }
        });

        return;
      }

      if(currentY - scroll < -row.Height){
        // Reset frames for out of frame rows so they fade back in
        row.Elements.forEach(el => {
          if(el.Type === PhotoListElementType.PHOTO){
            (el as PhotoListPhoto).Photo.frames = 0;
            (el as PhotoListPhoto).Photo.shown = false;
          }
        });

        currentY += row.Height + 10;
        continue;
      }
      
      // === DEBUG ===
      // ctx.strokeStyle = '#f00';
      // ctx.strokeRect((canvas.width / 2) - row.Width / 2, currentY - 5 - scroll, row.Width, row.Height + 10);

      // Loop through all elements in the row
      let rowXPos = 10;
      for (let j = 0; j < row.Elements.length; j++) {
        let el = row.Elements[j];

        switch(el.Type){
          case PhotoListElementType.TEXT:
            // If it is a text element we should centre the text in the middle of the canvas
            // and then render that text

            // === DEBUG ===
            // ctx.strokeStyle = '#f00';
            // ctx.strokeRect(0, currentY - scroll, canvas.width, row.Height);

            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.globalAlpha = 1;
            ctx.fillStyle = '#fff';
            ctx.font = '30px Rubik';

            ctx.fillText((el as PhotoListText).Text, canvas.width / 2, currentY - scroll + 25);
            break;
          case PhotoListElementType.PHOTO:
            let photo = (el as PhotoListPhoto).Photo;

            // === DEBUG ===
            // ctx.strokeStyle = '#f00';
            // ctx.strokeRect((rowXPos - row.Width / 2) + canvas.width / 2, currentY - scroll, photo.scaledWidth!, row.Height);

            if(!photo.loaded)
              // If the photo is not loaded, start a new task and load it in that task
              setTimeout(() => photo.loadImage(), 1);
            else{
              photo.shown = true;

              photo.x = (rowXPos  - row.Width / 2) + canvas.width / 2;
              photo.y = currentY - scroll;

              // Photo is already loaded so we should draw it on the application
              ctx.globalAlpha = photo.frames / 100;
              ctx.drawImage(photo.image!, (rowXPos  - row.Width / 2) + canvas.width / 2, currentY - scroll, photo.scaledWidth!, photo.scaledHeight!);

              if(photo.isMultiLayer)
                ctx.drawImage(multilayerIcon, ((rowXPos  - row.Width / 2) + canvas.width / 2) + 5, (currentY - scroll) + 5, 20, 20);

              if(photo.frames < 100)
                photo.frames += 10;
            }
            
            rowXPos += photo.scaledWidth! + 10;
            break;
        }
      }
      
      currentY += row.Height + 10;
    }

    if(!this._isLoading){
      console.log('Loading more photos...');
      this._isLoading = true;

      window.PhotoManager.LoadSomeAndReloadFilters()
        .then(() => {
          this._isLoading = false;
        });
    }
  }
}