// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: deep-brown; icon-glyph: apple-alt;
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: deep-gray; icon-glyph: magic;
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: deep-green; icon-glyph: bus-alt;

/**
 * Author: Frederik Arnold
 * Github: https://github.com/Kiwifed0r/widgets
 * 
 * Copyright 2022 Frederik Arnold
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at

 *   http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */


class WeekInfo {
  
  constructor(date, harvestId, week, year) {
    this.date = date;
    this.harvestId = harvestId;
    this.week = week;
    this.year = year;
  }
}

class Vegetable {
  
  constructor(name, producer, info, imageId, iconId, is_additional) {
    this.name = name;
    this.producer = producer;
    this.info = info;
    this.imageId = imageId;
    this.iconId = iconId;
    this.isAdditional = is_additional;
  }
}

const COLOR_GREEN = new Color('#08cc33');
const COLOR_ORANGE = new Color('#F6CA35');
const COLOR_RED = new Color('#d03913');
const COLOR_GREY = new Color('#494949');

const FONT_TITLE = Font.boldSystemFont(12);
const FONT_TEXT = Font.regularSystemFont(12);
const FONT_SMALL_TEXT = Font.regularSystemFont(11);
const FONT_TINY_TEXT = Font.regularSystemFont(9);

const SMALL_SHARE_TYPE = 2;
const NORMAL_SHARE_TYPE = 1;

const DASHBOARD_URL = 'https://app.kartoffelkombinat.de/api/dashboard';
const SHARE_URL = 'https://app.kartoffelkombinat.de/api/shares/';
const IMAGE_URL = 'https://app.kartoffelkombinat.de/api/images/';
const LINK_URL = 'https://app.kartoffelkombinat.de/';

const WEEK_INFO_CACHE_NAME = 'week_info';
const VEGETABLES_CACHE_NAME = 'vegetables';
const CACHE_LIMIT_IN_SEC = 60 * 60 * 6;

const param = args.widgetParameter;
let shareType = NORMAL_SHARE_TYPE;

if (param != null && param.trim().length > 0) {
  if (param === 'klein') {
    shareType = SMALL_SHARE_TYPE;
  }
}

let widget;
let vegetables = null;
let weekInfo = null;

try {
  weekInfo = await getWeekInfo();
  vegetables = await getVegetables(weekInfo.harvestId, shareType);
} catch(error) {
  widget = await createErrorWidget(error);
}

if (vegetables != null) {
  widget = await createWidget(vegetables);
}

if(!config.runsInWidget) {
  await widget.presentSmall();
}

if (weekInfo) {
  widget.url = LINK_URL + 'ernteanteile/' + shareType + '/' + weekInfo.year + '/' + weekInfo.week;
} else {
  widget.url = LINK_URL;
}

Script.setWidget(widget);
Script.complete();

async function createErrorWidget(error) {
  const widget = new ListWidget();
  const errorWidget = widget.addText(error);
  return widget;
}

async function createWidget(vegetables) {
  const widget = new ListWidget();
  widget.setPadding(8, 16, 8, 8);

  const titleWidget = widget.addText('Gemüseherold');
  titleWidget.font = FONT_TITLE;
  titleWidget.textColor = COLOR_GREEN;

  const weekContainerWidget = widget.addStack();
  weekContainerWidget.layoutHorizontally();
  weekContainerWidget.addSpacer(6);

  const weekWidget = weekContainerWidget.addText(weekInfo.date);
  weekWidget.font = FONT_TINY_TEXT;
  weekWidget.textColor = COLOR_ORANGE;

  const container = widget.addStack();
  container.layoutHorizontally();

  container.addSpacer(6);
  
  const stack1 = container.addStack();
  stack1.layoutVertically();

  container.addSpacer(3);

  const stack2 = container.addStack();
  stack2.layoutVertically();
  
  if (vegetables.length > 0) {
    for (let i = 0; i < vegetables.length && i < 7; i++) {
      const vegetable = vegetables[i];      

      let name = vegetable.name;
      const producer = vegetable.producer;
      const info = vegetable.info;
      const imageId = vegetable.imageId;
      const iconId = vegetable.iconId;
      const isAdditional = vegetable.isAdditional;

      const image = await getImage(iconId);
      
      if (image) {
        const imageWidget = stack1.addImage(image);
        imageWidget.imageSize = new Size(15, 15);
      }
      
      if (isAdditional === 1 && info) {
        name += ' (' + info + ')';
      }

      const vegetableNameWidget = stack2.addText(name);
      vegetableNameWidget.font = FONT_TEXT;
      vegetableNameWidget.lineLimit = 1;

      if (isAdditional === 1) {
        vegetableNameWidget.textColor = COLOR_GREY;
      }  
      
      if (i < vegetables.length - 1) {
        stack2.addSpacer(1);
      }
    }
  } else {
    widget.addSpacer();
    const noVegetablesWidget = widget.addText('Kein Gemüse! 😱');
    noVegetablesWidget.font = FONT_TEXT;
    noVegetablesWidget.textColor = COLOR_RED;
    noVegetablesWidget.centerAlignText();
  }
  
  if (vegetables.length < 7) {
    widget.addSpacer();
  }

  const footerWidget = widget.addStack();
  footerWidget.layoutHorizontally();
  footerWidget.addSpacer();
    
  const dateFormatter = new DateFormatter();
  dateFormatter.useShortDateStyle();
  dateFormatter.useShortTimeStyle();
    
  const updated = dateFormatter.string(new Date(Date.now()));
  const updatedWidget = footerWidget.addText(updated);
  
  updatedWidget.font = FONT_TINY_TEXT;
  updatedWidget.textColor = COLOR_GREY;
  updatedWidget.rightAlignText();
  
  return widget;
}

async function getWeekInfo() {
  const nowInSec = Math.floor(Date.now() / 1000);
  let result = getFromCache(WEEK_INFO_CACHE_NAME);

  if (result == null || (nowInSec - result.lastUpdated > CACHE_LIMIT_IN_SEC)) {
    try {
      result = await loadJsonFromServer(DASHBOARD_URL);
      result.lastUpdated = nowInSec;
      saveToCache(WEEK_INFO_CACHE_NAME, result);
    } catch (error) {
      throw 'Es ist ein Fehler aufgetreten 😕';
    }
  }
  
  if (result.next && result.next.date && result.next.harvest_id) {
    return new WeekInfo(result.next.date, result.next.harvest_id, result.next.week, result.next.year);
  } else if (result.this) {
    return new WeekInfo(result.this.date, result.this.harvest_id, result.this.week, result.this.year);
  }
  
  throw 'Info konnte nicht geladen werden!';
}
  
async function getVegetables(harvestId, shareType) {
  const nowInSec = Math.floor(Date.now() / 1000);
  let result = getFromCache(VEGETABLES_CACHE_NAME);

  if (result == null || (result.share_type !== shareType) || (nowInSec - result.lastUpdated > CACHE_LIMIT_IN_SEC)) {
    try {
      const url = SHARE_URL + shareType + '/' + harvestId;
      result = await loadJsonFromServer(url);
      result.lastUpdated = nowInSec;
      saveToCache(VEGETABLES_CACHE_NAME, result);
    } catch (error) {
      throw 'Es ist ein Fehler aufgetreten 😕';
    }
  }
  
  const vegetables = [];
  
  if (result.crops) {
    for (let i in result.crops) {
      const vegetable = result.crops[i];
      const name = vegetable.name;
      const producer = vegetable.producer;
      const info = vegetable.info;
      const imageId = vegetable.image.id;
      const iconId = vegetable.icon.id;
      const isAdditional = vegetable.is_additional;
      
      vegetables.push(new Vegetable(name, producer, info, imageId, iconId, isAdditional));
    }
  }
  
  return vegetables;
}

async function loadJsonFromServer(url) {
  const request = new Request(url);
  return await request.loadJSON();
}

function saveToCache(name, jsonStruct) {
  const fileManager = FileManager.local();
  const rootDir = fileManager.documentsDirectory();
  const dir = fileManager.joinPath(rootDir, 'gemueseherold');

  if (!fileManager.fileExists(dir)) {
    fileManager.createDirectory(dir);
  }

  const path = fileManager.joinPath(dir, name + '.json');
  fileManager.writeString(path, JSON.stringify(jsonStruct));
}

function getFromCache(name) {
  const fileManager = FileManager.local();
  const rootDir = fileManager.documentsDirectory();
  const dir = fileManager.joinPath(rootDir, 'gemueseherold');
  const path = fileManager.joinPath(dir, name + '.json');

  if (fileManager.fileExists(path)) {
      const fileContent = fileManager.readString(path);
      
      try {
        return JSON.parse(fileContent);
      } catch (err) {
        fileManager.remove(path);
      }
  }

  return null;
}

async function getImage(imageId) {
  const fileManager = FileManager.local();
  const rootDir = fileManager.documentsDirectory();
  const dir = fileManager.joinPath(rootDir, 'gemueseherold');

  if (!fileManager.fileExists(dir)) {
    fileManager.createDirectory(dir);
  }

  const path = fileManager.joinPath(dir, imageId + '.png');

  if (fileManager.fileExists(path)) {
      try {
        return fileManager.readImage(path);
      } catch (err) {
        fileManager.remove(path);
      }
  } else {
      try {
        let iconImage = await loadImage(IMAGE_URL + imageId);
        fileManager.writeImage(path, iconImage);
        return iconImage;
      } catch (err) {
      }
  }
  return null;
}

async function loadImage(imageUrl) {
  const req = new Request(imageUrl);
  return await req.loadImage();
}