import $ from 'jquery';
import * as JSX from './jsx';
import * as api from './api';
import * as user from './user';
import * as chat from './chat';

import { Page } from './components';
import { ChatInput, ChatList } from './chat';

let start_w = 0, start_h = 0;
let start_mx = 0, start_my = 0;
let is_resizing = false;
let has_listener = false;

function startResize( e: MouseEvent ) {
  const terminal = $( "#terminal" );
  start_mx = e.pageX;
  start_my = e.pageY;
  
  if( terminal[0].style.width )
    start_w = parseInt( terminal[0].style.width );
  else
    start_w = terminal[0].clientWidth;
  
  if( terminal[0].style.height )
    start_h = parseInt( terminal[0].style.height );
  else
    start_h = terminal[0].clientHeight * 1.05;

  window.addEventListener( "touchmove", resize );
  window.addEventListener( "touchend", saveSize );
  window.addEventListener( "touchcancel", saveSize );
  window.addEventListener( "mousemove", resize );
  window.addEventListener( "mouseup", saveSize );
  is_resizing = true;
}

function resize( e: MouseEvent ) {
  if( !is_resizing )
    return;

  let new_w = start_w + ( e.pageX - start_mx ) * 2.0;
  let new_h = start_h + ( ( e.pageY - start_my ) * 1.05 );

  const body = $( "body" );
  const max_h = body.outerHeight() - 60;

  if( new_h > max_h )
    new_h = max_h;

  const terminal = $( "#terminal" );

  terminal.css( `width`, `${ new_w }px` );
  terminal.css( `height`, `${ new_h }px` );
}

function saveSize() {
  if( !is_resizing )
    return;

  const terminal = $( "#terminal" );
  let size = {
    width: terminal[0].style.width,
    height: terminal[0].style.height,
  };

  is_resizing = false;
  localStorage.setItem( "terminal-size", JSON.stringify( size ) );

  window.removeEventListener( "touchmove", resize );
  window.removeEventListener( "touchend", saveSize );
  window.removeEventListener( "touchcancel", saveSize );
  window.removeEventListener( "mousemove", resize );
  window.removeEventListener( "mouseup", saveSize );
}

function getStyleForSize() {
  let style = "";
  if( window.innerWidth > 768 ) {
    const size_settings = localStorage.getItem( "terminal-size" );
    if( size_settings ) {
      const parsed = JSON.parse( size_settings );
      style = `width: ${ parsed.width }; height: ${ parsed.height };`;
    }
  }
  else {
    style = `width: 95%; height: ${Math.floor( window.innerHeight - 130 )}px`;
  }

  return style;
}

function onWindowResize() {
  const terminal = $( "#terminal" );
  const style = getStyleForSize();
  terminal.attr( "style", style );

  if( window.innerWidth < 768 )
    $( "#terminal-resizer" ).hide();
  else
    $( "#terminal-resizer" ).show();
}

function focusInput( e: Event ) {
  const sel = window.getSelection();
  if( sel && sel.type == 'Range' )
    return;

  const input = $( "#cmd-input" );
  const content = input.find( "#input-content" );
  if( !input.length || !content.length )
    return;

  for( let iclass of ( e.target as HTMLElement )?.classList ) {
    if( iclass.startsWith( "tool-call" ) )
      return;
  }

  input[0].focus();

  // move cursor to the end of text
  if( sel.anchorNode != content[0] && sel.anchorNode.parentElement != content[0] ) {
    const range = document.createRange();
    if( content.length ) {
      const child = content[0].firstChild;
      if( child ) {
        range.setStart( child, 0 );
        range.setEnd( child, child.textContent.length );
      }
      else {
        range.selectNodeContents( content[0] );
      }
      range.collapse( false );

      sel.removeAllRanges();
      sel.addRange( range );
    }
  }
}

function TerminalResizer( props: any ) {
  return <div id="terminal-resizer"
    onmousedown={ startResize }
    ontouchstart={ startResize }
    style={ props.style || '' }
  />
}

let promptc = 0;
function writePrompt( promptTxt: string ) {
  let el = $(
    <div id={ `prompt-${promptc++}` } onclick={ () => inputPrompt( promptTxt ) }>
      <a href="#"></a>
    </div>
  );

  let writeChar = ( str: string, i: number ) => {
    if( i >= str.length )
      return;

    let char = str.charAt( i );
    let link = el.find( 'a' );
    let text = link.text();
    link.text( text + char );
    setTimeout( () => writeChar( str, i + 1 ), 50 );
  };

  writeChar( promptTxt, 0 );
  $( '#suggested-prompts' ).append( el );
}

async function getPrompts() {
  const prompts_req = await fetch( `${window.location.origin}/static/prompts.json` );
  const data = await prompts_req.json();
  const { prompts } = data;

  const shuffled = prompts.sort( () => Math.random() - 0.5 );
  const random_prompts = shuffled.slice( 0, 5 );

  random_prompts.forEach( ( p: string ) => {
    writePrompt( p );
  } );
}

function inputPrompt( txt: string ) {
  const input = $( "#cmd-input" );
  const el = input[0] as HTMLInputElement;

  input.text( txt );
  input[0].focus();

  let range = document.createRange()
  let sel = window.getSelection()

  range.setStart( el.childNodes[0], txt.length );
  range.collapse( true )

  sel.removeAllRanges()
  sel.addRange( range )
}

function SuggestedPrompts() {
  setTimeout( () => {
    if( !chat.msglog.length )
      getPrompts();
  } );

  return <div id="suggested-prompts">
  </div>
}

function TerminalWindow() {
  if( !has_listener ) {
    window.onresize = onWindowResize;
    has_listener = true;
  }

  const style = getStyleForSize();
  return <div id="terminal" style={ style } onclick={ focusInput }>
    <div id="terminal-header">
      <div>
        <div id="chat-name">new chat</div>
        <a href="#" onclick={ () => JSX.navigateParams( "/terminal", {} ) }>X</a>
      </div>
    </div>
    <div id="terminal-inner">
      <ChatInput />
      <SuggestedPrompts />
    </div>
    <div>
      <TerminalResizer style={ window.innerWidth <= 768 ? "display: none" : ""  } />
    </div>
  </div>
}

function ModelCapabilities() {
  const model = api.getModelFromName( user.settings.site_prefs.model! );
  if( !model )
    return <div />

  const capabilities = model.capabilities;
  if( !capabilities )
    return <div />

  let model_str = `${model.name} | `;
  model_str += `vision ${capabilities.vision ? '✔' : '✘'} | `;
  model_str += `web ${capabilities.web ? '✔' : '✘'} | `;
  model_str += `notes ${capabilities.notes ? '✔' : '✘'} | `;
  model_str += `memory lookup ${capabilities.remind ? '✔' : '✘'}`;
  // todo: later
  // model_str += ` | reasoning ${capabilities.reasoning ? '✔' : '✘'}`;

  return <div id="model-capabilities">
    { model_str }
  </div>
}

export function updateCapabilitiesDisplay() {
  const div = $( "#model-capabilities" );
  if( div.length > 0 )
    div.replaceWith( <ModelCapabilities /> );
}

export default function Terminal() {
  if( !user.is_loggedin ) {
    setTimeout( () => JSX.navigate( "/" ) );
    return <Page>not logged in</Page>
  }

  return <Page>
    <TerminalWindow />
    <ModelCapabilities />
    <ChatList />
  </Page>
}
