import {inject, Injectable} from '@angular/core';
import {TuiAlertService} from '@taiga-ui/core';
import {DatabaseAPI} from '@chatenium/chatenium-sdk/storage/database';

@Injectable({
  providedIn: 'root'
})
export class IndexedDB {
  private dbVersion = 3
  private db: IDBDatabase | null = null

  getApi(): DatabaseAPI {
    return {
      get: async (collection, key) => {
        return await this.get(collection, key)
      },
      set: (collection, key, value) => {
        return this.putObject(collection, value, key);
      },
      flush: () => {},
      delete: (collection, key) => {
        return this.delete(collection, key);
      }
    }
  }

  openDatabase(): Promise<void> {
    return new Promise(resolve => {
      const request = indexedDB.open("cache", this.dbVersion);

      request.onupgradeneeded = (e: IDBVersionChangeEvent) => {
        const db = (e.target as IDBOpenDBRequest).result;
        db.createObjectStore('sessions', { keyPath: 'id' })
        db.createObjectStore('chats', { keyPath: 'id' })
        db.createObjectStore('networks', { keyPath: 'id' })
        db.createObjectStore('files', { keyPath: 'id' })
        db.createObjectStore('messages', { keyPath: 'id' })
        db.createObjectStore('networkmessages', { keyPath: 'id' })
        db.createObjectStore('pictures', { keyPath: 'id' })
      }

      request.onsuccess = (event: Event) => {
        this.db = (event.target as IDBOpenDBRequest).result;
        console.log("Indexed DB Successfully opened")
        resolve()
      }

      request.onerror = _ => {
        const request = indexedDB.deleteDatabase("cache");
        request.onsuccess = _ => {
          setTimeout(() => {
            console.log("Recreated the database.")
            location.reload()
          }, 1500)
        }

        request.onerror = _ => {
          console.error("Fatal error. Cannot access indexedDB, check if access is not blocked.")
        }
      }
    })
  }

  public putObject(storeName: string, data: any, id: string) {
    if (this.db) {
      const request = this.db.transaction([storeName], 'readwrite')
        .objectStore(storeName)
        .put({id: id, data: data})

      request.onerror = _ => {
        console.error("[IDB] ERROR: Adding data failed.")
      }
    } else {
      console.error("[IDB] ERROR: DB Not open. Retrying in 500ms...")

      setTimeout(() => {
        console.log("Retrying now...")
        this.putObject(storeName, data, id)
      }, 1000)
    }
  }

  clearObjectStore(storeName: string) {
    return new Promise((resolve, reject) => {
      if (this.db) {
        const transaction = this.db.transaction([storeName], "readwrite");
        const store = transaction.objectStore(storeName);
        const request = store.clear();

        request.onsuccess = () => {
          resolve("Ok");
        };

        request.onerror = () => {
          console.error("Getting chats cache failed");
          reject([]);
        };
      } else {
        console.error("DB NOT OPEN (CLEAROBJECTSTORE)")
      }
    });
  }


  getAll(storeName: string): Promise<any> {
    return new Promise((resolve, reject) => {
      if (this.db) {
        const transaction = this.db.transaction([storeName], "readonly");
        const store = transaction.objectStore(storeName);
        const request = store.getAll();

        request.onsuccess = () => {
          resolve(request.result.map((data) => data.data));
        };

        request.onerror = () => {
          console.error("Getting chats cache failed");
          reject([]);
        };
      } else {
        console.error("DB NOT OPEN (GETALL)")
      }
    });
  }

  get(storeName: string, key: string): Promise<string> {
    return new Promise((resolve, reject) => {
      if (this.db) {
        const transaction = this.db.transaction([storeName], "readonly");
        const store = transaction.objectStore(storeName);
        const request = store.get(key);

        request.onsuccess = () => {
          resolve(request.result == null ? [] : request.result.data);
        };

        request.onerror = () => {
          console.error("Getting chats cache failed");
          reject([]);
        };
      } else {
        console.error("[IDB GET] ERROR: DB Not open.")
      }
    });
  }

  delete(storeName: string, key: string): Promise<void> {
    return new Promise((resolve, reject) => {
      if (this.db) {
        const transaction = this.db.transaction([storeName], "readonly");
        const store = transaction.objectStore(storeName);
        const request = store.delete(key);

        request.onsuccess = () => {
          resolve();
        };

        request.onerror = () => {
          console.error("Getting chats cache failed");
          reject([]);
        };
      } else {
        console.error("[IDB GET] ERROR: DB Not open.")
      }
    });
  }
}
