// Copyright (C) 2020 The Android Open Source Project
//
// 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.

import {getDefaultRecordingTargets, RecordingTarget} from '../common/state';
import {
  createEmptyRecordConfig,
  NamedRecordConfig,
  namedRecordConfigValidator,
  RecordConfig,
  recordConfigValidator,
} from '../controller/record_config_types';
import {runValidator, ValidationResult} from '../controller/validators';

const LOCAL_STORAGE_RECORD_CONFIGS_KEY = 'recordConfigs';
const LOCAL_STORAGE_AUTOSAVE_CONFIG_KEY = 'autosaveConfig';
const LOCAL_STORAGE_RECORD_TARGET_OS_KEY = 'recordTargetOS';

export class RecordConfigStore {
  recordConfigs: Array<ValidationResult<NamedRecordConfig>>;
  recordConfigNames: Set<string>;

  constructor() {
    this.recordConfigs = [];
    this.recordConfigNames = new Set();
    this.reloadFromLocalStorage();
  }

  private _save() {
    window.localStorage.setItem(
        LOCAL_STORAGE_RECORD_CONFIGS_KEY,
        JSON.stringify(this.recordConfigs.map((x) => x.result)));
  }

  save(recordConfig: RecordConfig, title?: string): void {
    // We reload from local storage in case of concurrent
    // modifications of local storage from a different tab.
    this.reloadFromLocalStorage();

    const savedTitle = title ? title : new Date().toJSON();
    const config: NamedRecordConfig = {
      title: savedTitle,
      config: recordConfig,
      key: new Date().toJSON(),
    };

    this.recordConfigs.push({result: config, invalidKeys: [], extraKeys: []});
    this.recordConfigNames.add(savedTitle);

    this._save();
  }

  overwrite(recordConfig: RecordConfig, key: string) {
    // We reload from local storage in case of concurrent
    // modifications of local storage from a different tab.
    this.reloadFromLocalStorage();

    const found = this.recordConfigs.find((e) => e.result.key === key);
    if (found === undefined) {
      throw new Error('trying to overwrite non-existing config');
    }

    found.result.config = recordConfig;

    this._save();
  }

  delete(key: string): void {
    // We reload from local storage in case of concurrent
    // modifications of local storage from a different tab.
    this.reloadFromLocalStorage();

    let idx = -1;
    for (let i = 0; i < this.recordConfigs.length; ++i) {
      if (this.recordConfigs[i].result.key === key) {
        idx = i;
        break;
      }
    }

    if (idx !== -1) {
      this.recordConfigNames.delete(this.recordConfigs[idx].result.title);
      this.recordConfigs.splice(idx, 1);
      this._save();
    } else {
      // TODO(bsebastien): Show a warning message to the user in the UI.
      console.warn('The config selected doesn\'t exist any more');
    }
  }

  private clearRecordConfigs(): void {
    this.recordConfigs = [];
    this.recordConfigNames.clear();
    this._save();
  }

  reloadFromLocalStorage(): void {
    const configsLocalStorage =
        window.localStorage.getItem(LOCAL_STORAGE_RECORD_CONFIGS_KEY);

    if (configsLocalStorage) {
      this.recordConfigNames.clear();

      try {
        const validConfigLocalStorage:
            Array<ValidationResult<NamedRecordConfig>> = [];
        const parsedConfigsLocalStorage = JSON.parse(configsLocalStorage);

        // Check if it's an array.
        if (!Array.isArray(parsedConfigsLocalStorage)) {
          this.clearRecordConfigs();
          return;
        }

        for (let i = 0; i < parsedConfigsLocalStorage.length; ++i) {
          try {
            validConfigLocalStorage.push(runValidator(
                namedRecordConfigValidator, parsedConfigsLocalStorage[i]));
          } catch {
            // Parsing failed with unrecoverable error (e.g. title or key are
            // missing), ignore the result.
            console.log(
                'Validation of saved record config has failed: ' +
                JSON.stringify(parsedConfigsLocalStorage[i]));
          }
        }

        this.recordConfigs = validConfigLocalStorage;
        this._save();
      } catch (e) {
        this.clearRecordConfigs();
      }
    } else {
      this.clearRecordConfigs();
    }
  }

  canSave(title: string) {
    return !this.recordConfigNames.has(title);
  }
}

// This class is a singleton to avoid many instances
// conflicting as they attempt to edit localStorage.
export const recordConfigStore = new RecordConfigStore();

export class AutosaveConfigStore {
  config: RecordConfig;

  // Whether the current config is a default one or has been saved before.
  // Used to determine whether the button to load "last started config" should
  // be present in the recording profiles list.
  hasSavedConfig: boolean;

  constructor() {
    this.hasSavedConfig = false;
    this.config = createEmptyRecordConfig();
    const savedItem =
        window.localStorage.getItem(LOCAL_STORAGE_AUTOSAVE_CONFIG_KEY);
    if (savedItem === null) {
      return;
    }
    const parsed = JSON.parse(savedItem);
    if (parsed !== null && typeof parsed === 'object') {
      this.config = runValidator(recordConfigValidator, parsed).result;
      this.hasSavedConfig = true;
    }
  }

  get(): RecordConfig {
    return this.config;
  }

  save(newConfig: RecordConfig) {
    window.localStorage.setItem(
        LOCAL_STORAGE_AUTOSAVE_CONFIG_KEY, JSON.stringify(newConfig));
    this.config = newConfig;
    this.hasSavedConfig = true;
  }
}

export const autosaveConfigStore = new AutosaveConfigStore();

export class RecordTargetStore {
  recordTargetOS: string|null;

  constructor() {
    this.recordTargetOS =
        window.localStorage.getItem(LOCAL_STORAGE_RECORD_TARGET_OS_KEY);
  }

  get(): string|null {
    return this.recordTargetOS;
  }

  getValidTarget(): RecordingTarget {
    const validTargets = getDefaultRecordingTargets();
    const savedOS = this.get();

    const validSavedTarget = validTargets.find((el) => el.os === savedOS);
    return validSavedTarget || validTargets[0];
  }

  save(newTargetOS: string) {
    window.localStorage.setItem(
        LOCAL_STORAGE_RECORD_TARGET_OS_KEY, newTargetOS);
    this.recordTargetOS = newTargetOS;
  }
}

export const recordTargetStore = new RecordTargetStore();
