/*
 * Copyright (C) 2022 StApps
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

import {Component, OnInit} from '@angular/core';
import {AddEventReviewModalComponent} from '../../calendar/add-event-review-modal.component';
import {ModalController} from '@ionic/angular/standalone';
import {ScheduleProvider} from '../../calendar/schedule.provider';
import {Directory, Encoding, Filesystem} from '@capacitor/filesystem';
import {Share} from '@capacitor/share';
import {Device} from '@capacitor/device';
import {Dialog} from '@capacitor/dialog';
import {SCUuid} from '@openstapps/core';
import {TranslateService} from '@ngx-translate/core';
import {StorageProvider} from '../../storage/storage.provider';
import {ScheduleSyncService} from '../../background/schedule/schedule-sync.service';
import {CalendarService} from '../../calendar/calendar.service';
import {getNativeCalendarExport} from '../../calendar/ical/ical';
import {ThingTranslateService} from '../../../translation/thing-translate.service';
import {
  CALENDAR_NOTIFICATIONS_ENABLED_KEY,
  CALENDAR_SYNC_ENABLED_KEY,
  CALENDAR_SYNC_KEYS,
  calendarSettingStorageKey,
  getCalendarSetting,
} from './calendar-sync-settings-keys';

@Component({
  selector: 'calendar-sync-settings',
  templateUrl: 'calendar-sync-settings.html',
  styleUrls: ['calendar-sync-settings.scss'],
})
export class CalendarSyncSettingsComponent implements OnInit {
  isWeb = true;

  syncEnabled = false;

  notificationsEnabled = false;

  constructor(
    readonly modalController: ModalController,
    readonly scheduleProvider: ScheduleProvider,
    readonly translator: TranslateService,
    readonly thingTranslator: ThingTranslateService,
    readonly storageProvider: StorageProvider,
    readonly scheduleSyncService: ScheduleSyncService,
    readonly calendarService: CalendarService,
  ) {}

  ngOnInit() {
    Device.getInfo().then(it => {
      this.isWeb = it.platform === 'web';
    });

    this.getSetting(CALENDAR_SYNC_ENABLED_KEY).then(it => (this.syncEnabled = it));
    this.getSetting(CALENDAR_NOTIFICATIONS_ENABLED_KEY).then(it => (this.notificationsEnabled = it));
  }

  async getSetting(key: CALENDAR_SYNC_KEYS, defaultValue = false): Promise<boolean> {
    return getCalendarSetting(this.storageProvider, key, defaultValue);
  }

  async syncCalendar(sync: boolean) {
    this.syncEnabled = sync;

    if (sync) {
      const uuids = this.scheduleProvider.partialEvents$.value.map(it => it.uid);
      const dateSeries = (await this.scheduleProvider.getDateSeries(uuids)).dates;

      await this.calendarService.syncEvents(
        getNativeCalendarExport(dateSeries, this.thingTranslator.translator),
      );
    } else {
      await this.calendarService.purge();
    }
  }

  async setSetting(settings: Partial<Record<CALENDAR_SYNC_KEYS, boolean>>) {
    await Promise.all(
      Object.entries(settings).map(([key, setting]) =>
        this.storageProvider.put(calendarSettingStorageKey(key), setting),
      ),
    );

    return this.scheduleSyncService.enable();
  }

  async export() {
    const uuids = this.scheduleProvider.partialEvents$.value.map(it => it.uid);
    const dateSeries = (await this.scheduleProvider.getDateSeries(uuids)).dates;

    const modal = await this.modalController.create({
      component: AddEventReviewModalComponent,
      canDismiss: true,
      cssClass: 'add-modal',
      componentProps: {
        dismissAction: () => {
          modal.dismiss();
        },
        dateSeries: dateSeries,
      },
    });

    await modal.present();
    await modal.onWillDismiss();
  }

  async restore(event: Event) {
    // @ts-expect-error files do actually exist
    const file = event.target?.files[0] as File;
    const uuids = JSON.parse(await file.text()) as SCUuid[] | unknown;
    if (!Array.isArray(uuids) || uuids.some(it => typeof it !== 'string')) {
      return Dialog.alert({
        title: this.translator.instant('settings.calendar.export.dialogs.restore.rejectFile.title'),
        message: this.translator.instant('settings.calendar.export.dialogs.restore.rejectFile.message'),
      });
    }
    const dateSeries = await this.scheduleProvider.restore(uuids);
    return dateSeries
      ? Dialog.confirm({
          title: this.translator.instant('settings.calendar.export.dialogs.restore.success.title'),
          message: this.translator.instant('settings.calendar.export.dialogs.restore.success.message'),
        })
      : Dialog.alert({
          title: this.translator.instant('settings.calendar.export.dialogs.restore.error.title'),
          message: this.translator.instant('settings.calendar.export.dialogs.restore.error.message'),
        });
  }

  translateWithDefault(key: string, defaultValue: string) {
    const out = this.translator.instant(key);
    return out === key ? defaultValue : out;
  }

  async backup() {
    const uuids = JSON.stringify(this.scheduleProvider.partialEvents$.value.map(it => it.uid));

    const fileName = `${this.translator.instant('settings.calendar.export.fileName')}.json`;
    const info = await Device.getInfo();
    if (info.platform === 'web') {
      const blob = new Blob([uuids], {type: 'application/json'});
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = fileName;
      a.click();
      window.URL.revokeObjectURL(url);
    } else {
      const result = await Filesystem.writeFile({
        path: fileName,
        data: uuids,
        encoding: Encoding.UTF8,
        directory: Directory.Cache,
      });

      await Share.share({
        title: this.translator.instant('settings.calendar.export.dialogs.backup.save.title'),
        text: this.translator.instant('settings.calendar.export.dialogs.backup.save.message'),
        url: result.uri,
        dialogTitle: this.translator.instant('settings.calendar.export.dialogs.backup.save.title'),
      });
    }
  }
}
