import $ from 'jquery';

import * as JSX from './jsx';
import * as api from './api';

export interface ChatFile {
  id: string,
  name: string
}

export interface UserSettings {
  uuid: string,
  nickname: string,
  site_prefs: {
    font: string,
    model?: string
  },
  prompt_data: {
    system?: string
  },
  chat_files?: {
    files?: ChatFile[]
  },
  plan: {
    endTime: number,
    plan: string
  }
};

export let is_loggedin = false;
export let settings: UserSettings = null;

let on_prefs_updated: Function = () => {};

export async function onPrefsUpdated( fn: Function ) {
  on_prefs_updated = fn;
}

/**
 * polls settings from the server
**/
export async function updatePrefs() {
  if( !is_loggedin ) {
    return;
  }

  let res = null;
  try {
    res = await fetch( `${api.url}/settings`, {
      method: 'POST',
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify( {
        token: localStorage.getItem( 'session' ),
      } )
    } );

    if( !res.ok ) {
      try {
        const json = await res.json();
        if( json.status == 'nodata' ) {
          localStorage.setItem( 'needs-setup', 'true' );
          if( window.location.pathname != '/first-landing' )
            return JSX.navigate( '/first-landing' );
          else {
            settings = null;
            localStorage.setItem( 'settings', '{}' );
          }
        } else if( json.status != 'ok' ) {
          is_loggedin = false;
          localStorage.clear();
        }

        throw new Error( json.msg );
      } catch( e: any ) {
        throw new Error( "error contacting server" );
      }
    }

    res = await res.json();
  } catch( e: any ) {
    throw new Error( e.message );
  }

  settings = res.userprefs;
  localStorage.setItem( 'settings', JSON.stringify( settings ) );
  on_prefs_updated();
}

/**
 * saves prefs on the server
**/
export async function savePrefs( prefs: any ) {
  const res = await api.post( `update-settings`, { token: localStorage.getItem( 'session' ), prefs } );
  settings = res.userprefs;
  localStorage.setItem( 'settings', JSON.stringify( settings ) );
}

export async function getNotes() {
  const res = await api.post( `get-notes`, { token: localStorage.getItem( 'session' ) } );
  return res.notes;
}

export async function deleteNote( note_id: string ) {
  await api.post( `delete-note`, { token: localStorage.getItem( 'session' ), noteId: note_id } );
}

export async function deleteAllNotes() {
  await api.post( `delete-notes`, { token: localStorage.getItem( 'session' ) } );
}

export async function getTokens() {
  const res = await api.post( `get-tokens`, { token: localStorage.getItem( 'session' ) } );
  return res.tokens;
}

export async function createToken() {
  const res = await api.post( `create-token`, { token: localStorage.getItem( 'session' ) } );
  return res.token;
}

export async function deleteToken( token_id: number ) {
  await api.post( `delete-token`, { id: token_id, token: localStorage.getItem( 'session' ) } );
}

export async function deleteAllTokens() {
  await api.post( `delete-tokens`, { token: localStorage.getItem( 'session' ) } );
}

export async function createChat() {
  const res = await api.post( `create-chat`, { token: localStorage.getItem( 'session' ) } );
  return res;
}

export async function deleteChat( chatId: string ) {
  await api.post( `delete-chat`, { chatId, token: localStorage.getItem( 'session' ) } );
}

export async function downloadAllData() {
  let res = await fetch( `${api.url}/getalldata`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify( { token: localStorage.getItem( 'session' ) } )
  } );

  let contentType = res.headers.get( 'content-type' );
  if( contentType && contentType.includes( 'application/zip' ) ) {
    let blob = await res.blob();
    let url = window.URL.createObjectURL( blob );
    const a = <a style="display:none" href={url} download="userdata.zip"/>;
    $( 'body' ).append( a );
    a.onclick = ( e: Event ) => { e.stopPropagation(); };
    a.click();
    window.URL.revokeObjectURL( url );
  }
  else {
    let json = null;
    try {
      json = await res.json();
    } catch( e: any ) {
      throw new Error( "Error contacting server" );
    }

    if( json.status != 'ok' )
      throw new Error( json.msg );
  }
}

export async function invalidateAllSessions() {
  const res = await api.post( `invalidate-all-sessions`, { token: localStorage.getItem( 'session' ) } );
  localStorage.setItem( 'session', res.session );
}

function updateFont() {
  const style = document.documentElement.style;
  if( settings.site_prefs && settings.site_prefs.font != null )
    style.setProperty( "--site-font", settings.site_prefs.font );
}

async function onNavigateAsync() {
  try {
    if( is_loggedin ) {
      if( localStorage.getItem( 'needs-setup' ) && window.location.pathname !== "/first-landing" )
        setTimeout( () => JSX.navigate( "/first-landing" ) );
      else
        await updatePrefs();
      // update it again in case it changed in prefs
      updateFont();
    }

    await api.updateModels();
  } catch( e: any ) {
    // todo: display message box w error
    console.log( e );
  }
}

export function onNavigate() {
  settings = JSON.parse( localStorage.getItem( 'settings' ) || '{}' ) as UserSettings;
  api.parseModels();
  if( localStorage.getItem( 'session' ) )
    is_loggedin = true;

  if( is_loggedin )
    updateFont();

  onNavigateAsync();
}

/**
 * returns true on success, error message on failure
**/
export async function sendLoginLink( email: string ) {
  let res = null;
  try {
    res = await api.post( `send-login-link`, { email } );
  } catch( e: any ) {
    return e.message;
  }

  return true;
}

export async function onLogin( code: string ) {
  let json = null;
  try {
    const res = await fetch( `${api.url}/login?token=${code}` );
    json = await res.json();
  } catch( e: any ) {
    throw new Error( "error contacting server" );
  }

  if( json.status != 'ok' )
    throw new Error( json.msg );

  localStorage.setItem( 'session', json.session );
  is_loggedin = true;

  try {
    await updatePrefs();
  } catch( e: any ) {
    throw new Error( e.msg );
  }
}

export async function logout() {
  if( !is_loggedin )
    return;

  try {
    await api.post( 'invalidate-session', { token: localStorage.getItem( 'session' ) } );
  } catch( e: any ) {}

  localStorage.clear();
  is_loggedin = false;
  JSX.navigate( '/' );
  window.location.reload();
}
