import $ from "jquery";
import * as JSX from "./jsx";
import * as api from "./api";
import * as util from "./util";
import * as user from "./user";
import * as terminal from "./terminal";
import {
  addPopup, onPopupClosed, closePopup,
  Dropdown, DropdownItem,
  Spinner,
  OkPopup, OkCancelPopup
} from "./components";

let old_font = '';
const fonts = [
  'Terminal',
  'Arial',
  'Monospace',
  'Sans-serif',
  'Serif',
  'Times'
];

function showDeleteTokenPopup( id: number ) {
  const deleteToken = async() => {
    try {
      await user.deleteToken( id );
      $( `#token-${ id }` ).remove();
    } catch( e: any ) {
      addPopup( $( <OkPopup>
        Error deleting token: { e.message }
      </OkPopup> ) );
    }
  }

  addPopup( $(
    <OkCancelPopup onclick={ deleteToken }>
      Are you sure you want to erase this API token?
    </OkCancelPopup>
  ) );
}

function showDeleteAllTokensPopup() {
  const deleteTokens = async() => {
    try {
      await user.deleteAllTokens();
      closePopup();
    } catch( e: any ) {
      addPopup( $( <OkPopup>
        Error deleting all tokens: { e.message }
      </OkPopup> ) );
    }
  }

  addPopup( $(
    <OkCancelPopup onclick={ deleteTokens }>
      Are you sure you want to erase all API tokens?
    </OkCancelPopup>
  ) );
}

function TokenEntry( props: any ) {
  const token = props.token;

  return <div class="tokens-entry" id={ `token-${ token.id }` }>
    <span>{ token.value }</span>
    <button class="tokens-delete" onclick={ () => showDeleteTokenPopup( token.id ) }>🗑</button>
  </div>
}

async function createNewToken( e: Event ) {
  const btn = $( e.target );

  e.preventDefault();
  e.stopPropagation();

  const spinner = $( <Spinner /> );
  btn.append( spinner );

  try {
    const token = await user.createToken();
    const tokens = await user.getTokens();
    // re-draw token popup
    closePopup();
    addPopup( $( <TokensPopup tokens={ tokens } /> ) );

    const copyTokenToClipboard = () => { navigator.clipboard.writeText( token ); }
    addPopup( $(
      <OkCancelPopup
        style="max-width: 330px; width: auto; text-align: center; display: flex; justify-content: center;"
        onclick={ copyTokenToClipboard }
      >
        Your api token has been created.<br />
        Make sure to save it as it will not be shown to you again.<br />
        <div style="background-color: #000; width: 100%; overflow: scroll; padding: 5px">
          { token }
        </div>

        Press OK to copy the token to clipboard.
      </OkCancelPopup>
    ) );
  } catch( e: any ) {
    addPopup( $(
      <OkPopup>
        Error creating token: { e.message }
      </OkPopup>
    ) );
  }

  spinner.remove();
}

function TokensPopup( props: any ) {
  return <div id="tokens-popup">
    { props.tokens.length > 0 &&
      <div id="tokens-inner">
        { props.tokens.map( ( tok: any ) => {
          return <TokenEntry token={tok} />
        } ) }
      </div>
    }
    {
      props.tokens.length == 0 && <div>
        No api tokens have been created.
      </div>
    }
    <div style="display: flex; margin-top: 10px;">
      <button class="settings-btn" style="width: 150px; margin-right: 5px" onclick={ createNewToken }>Create new token</button>
      <button class="settings-btn" style="width: 150px" onclick={ showDeleteAllTokensPopup }>Delete all tokens</button>
    </div>
  </div>
}

async function openTokensPopup() {
  let spinner = $( <Spinner /> );
  $( "#tokens-btn" ).append( spinner );
  try {
    const tokens = await user.getTokens();
    spinner.remove();

    return addPopup( $( <TokensPopup tokens={ tokens } /> ) );
  } catch( e: any ) {
    spinner.remove();
    return addPopup( $( <OkPopup>{ e.message }</OkPopup> ) );
  }
}


function showDeleteNotePopup( note_id: string ) {
  const deleteNote = async() => {
    try {
      await user.deleteNote( note_id );
      $( `#note-${ note_id }` ).remove();
    } catch( e: any ) {
      addPopup( $(
        <OkPopup>
          Error deleting note<br />{ e.message }
        </OkPopup>
      ) );
    }
  }

  addPopup( $(
    <OkCancelPopup onclick={ deleteNote }>
      Are you sure you want to delete this note?
    </OkCancelPopup>
  ) );
}

function showDeleteAllNotesPopup() {
  addPopup( $(
    <OkCancelPopup onclick={ async() => { await user.deleteAllNotes(); closePopup(); } }>
      Are you sure you want to delete all notes?
    </OkCancelPopup>
  ) );
}

function NotesPopup( props: any ) {
  return <div id="notes-popup">
    <div id="notes-inner">
      { props.notes.map( ( n: any ) => {
        return <div class="notes-entry" id={ `note-${ n.id }` }>
          <span>{ n.content.split(' : ')[1] }</span>
          <button class="notes-delete" onclick={ () => showDeleteNotePopup( n.id ) }>🗑</button>
        </div>
      } ) }
    </div>
    <div style="display: flex; margin-top: 10px;">
      <button class="settings-btn" style="width: 200px" onclick={ showDeleteAllNotesPopup }>Delete all notes</button>
    </div>
  </div>
}

async function openNotesPopup() {
  let spinner = $( <Spinner /> );
  $( "#notes-btn" ).append( spinner );
  try {
    const notes = await user.getNotes();
    spinner.remove();
    if( notes.length == 0 )
      return addPopup( $( <OkPopup>No notes found</OkPopup> ) );

    return addPopup( $( <NotesPopup notes={ notes } /> ) );
  } catch( e: any ) {
    spinner.remove();
    return addPopup( $( <OkPopup>{ e.message }</OkPopup> ) );
  }
}

function onSettingsClosed() {
  if( old_font.length > 0 ) {
    const style = document.documentElement.style;
    style.setProperty( "--site-font", old_font );
  }
}

function onFontChanged( e: Event ) {
  const el = $( e.target );
  const font = el.text();
  if( !old_font.length )
    old_font = user.settings.site_prefs.font;

  user.settings.site_prefs.font = font;
  const style = document.documentElement.style;
  style.setProperty( "--site-font", font );

  $( "#settings-font" ).text( font );
  closePopup();
}

function onModelChanged( e: Event ) {
  const el = $( e.target );
  const model = el.text();

  if( user.settings.plan.plan == 'free' ) {
    for( let m of api.models ) {
      if( m.name == model && !m.free ) {
        const popup = $( <OkCancelPopup onclick={ () => JSX.navigateParams( "/upgrade", {} ) }>
          This model is only available for paid users.
          Please upgrade your plan to use it.
        </OkCancelPopup> );

        return addPopup( popup );
      }
    }
  }

  user.settings.site_prefs.model = model;

  $( "#settings-model" ).text( model );
  closePopup();
}

async function save() {
  const newprefs = {
    site_prefs: user.settings.site_prefs,
    prompt_data: user.settings.prompt_data,
    nickname: user.settings.nickname
  };

  const newprompt = $( "#system-prompt" ).val();
  newprefs.prompt_data.system = newprompt as string;

  const newname = $( "#uname-setting" ).val() as string;
  if( newname.length > 1 )
    newprefs.nickname = newname;

  $( "#settings-spinner-wrapper" ).append( <Spinner /> );
  try {
    await user.savePrefs( newprefs );
  } catch( e: any ) {
    $( "#settings-spinner-wrapper" ).empty();
    $( "#settings-spinner-wrapper" ).append( <div class="settings-err">{ e.message }</div> );
    return;
  }

  old_font = '';
  $( "#settings-spinner-wrapper" ).empty();
  $( "#username" ).text( user.settings.nickname );
  $( "#uname-setting" ).attr( "placeholder", user.settings.nickname );
  terminal.updateCapabilitiesDisplay();
}

function PlanDisplay() {
  const el = $( <div style="margin-top: 10px; display: flex; justify-content: space-evenly" /> );
  if( user.settings.plan.plan == 'free' ) {
    el.append(
      <span>
        Plan: <b>free</b>&nbsp;
        <a onclick={ () => JSX.navigate( "/upgrade" ) }>[ upgrade ]</a>
      </span>
    );
  } else {
    el.append(
      <span>
        Plan: <b>{ user.settings.plan.plan }</b>
      </span>
    );

    let days_left = '';
    if( user.settings.plan.endTime == -1 )
      days_left = 'inf';
    else
      days_left = Math.floor( ( user.settings.plan.endTime - Date.now() ) / 60000 / 60 / 24 ).toString();
    el.append(
      <span>
        Time left: { days_left.toString() } days
      </span>
    );
  }

  return el[0];
}

async function downloadAllData() {
  const spinner = $( <Spinner /> );
  $( "#settings-spinner-wrapper" ).append( spinner );

  try {
    await user.downloadAllData();
  } catch( e: any ) {
    addPopup( $(
      <OkPopup>
        Error processing request: { e.message }
      </OkPopup>
    ) );
  }

  spinner.remove();
}

async function invalidateAllSessions() {
  const spinner = $( <Spinner /> );
  $( "#settings-spinner-wrapper" ).append( spinner );

  try {
    await user.invalidateAllSessions();
  } catch( e: any ) {
    addPopup( $(
      <OkPopup>
        Error invalidating sessions: { e.message }
      </OkPopup>
    ) );
  }

  spinner.remove();
}

function SettingsPopup() {
  return <div id="settings-popup">
    <div id="settings-top">
      <div>
        <label>System prompt</label><br/>
        <textarea maxlength="1024" placeholder="..." id="system-prompt">
          { util.escapeHtml( user.settings.prompt_data.system || '' ) }
        </textarea>
      </div>
      <div>
        <div class="chat-column">
          <label style="margin-bottom: 1px">Username</label>
          <input type="text" placeholder={ user.settings.nickname || '' } id="uname-setting" />
        </div>
        <div class="chat-column">
          <label>Site font</label>
          <Dropdown title={ user.settings.site_prefs.font } id="settings-font" inline>
            { fonts.map( ( f ) => <DropdownItem onclick={ onFontChanged }>{ f }</DropdownItem> ) }
          </Dropdown>
        </div>
        <div class="chat-column">
          <label>Chat model</label>
          <Dropdown title={ user.settings.site_prefs.model! } id="settings-model" inline>
            { api.models.map( ( m ) => {
              if( m.free || user.settings.plan.plan == 'paid' )
                return <DropdownItem onclick={ onModelChanged }>{ m.name }</DropdownItem>;
              return <DropdownItem onclick={ onModelChanged } style="color: #888">{ m.name }</DropdownItem>;
            } ) }
          </Dropdown>
        </div>
        <div style="display: flex; justify-content: space-between; margin-top: 10px">
          <button class="settings-btn" id="notes-btn" onclick={ openNotesPopup }>View notes</button>
          <button class="settings-btn" id="tokens-btn" onclick={ openTokensPopup }>View tokens</button>
        </div>
        <PlanDisplay />
      </div>
    </div>

    <div style="display: flex; flex-direction: column;">
      <button style="margin: 2px" onclick={ downloadAllData }>download all my data</button>
      <button style="margin: 2px" onclick={ invalidateAllSessions }>sign out all devices</button>
      <button style="margin: 2px" onclick={ save }>Save</button>
      <div id="settings-spinner-wrapper" />
    </div>
  </div>;
}

export function openPopup() {
  if( !user.is_loggedin )
    return;
  const el = $( <SettingsPopup /> );
  addPopup( el );
  onPopupClosed( onSettingsClosed );
}
