import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { encodeUtf8, type AdbSubprocessProtocol, type Adb } from '@yume-chan/adb'
import { Consumable, WritableStream } from '@yume-chan/stream-extra'
import { memo, useCallback, useEffect, useRef, useState } from 'react'

import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'

import 'xterm/css/xterm.css'

interface ShellTabProps {
  adb: Adb | undefined
}

export const ShellTab: React.FC<ShellTabProps> = memo(({ adb }) => {
  const [process, setProcess] = useState<AdbSubprocessProtocol | undefined>()
  const [terminal, setTerminal] = useState<Terminal | undefined>()

  const [reader, setReader] = useState<WritableStream<Uint8Array> | undefined>()

  useEffect(() => {
    if (adb) {
      console.log('adb is connected')

      console.log('creating terminal')
      const terminal: Terminal = new Terminal()
      terminal.options.cursorBlink = true
      terminal.options.theme = {
        background: '#1e1e1e',
        foreground: '#d4d4d4'
      }

      console.log('creating process')

      const _reader = new WritableStream<Uint8Array>({
        write(chunk) {
          terminal.write(chunk)
        }
      })

      adb.subprocess.shell('/data/data/com.termux/files/usr/bin/telnet localhost 45515').then(_process => {
        _process.stdout.pipeTo(_reader)

        const writer = _process.stdin.getWriter()
        terminal.onData(data => {
          const buffer = encodeUtf8(data)
          const consumable = new Consumable(buffer)
          writer.write(consumable)
        })

        setReader(_reader)
        setProcess(_process)
        setTerminal(terminal)
      })
    } else {
      console.log('adb is not connected')
      if (process) {
        process?.stdout.cancel()
        process?.stderr.cancel()
        process?.stdin.close()
        process?.kill()
      }

      setProcess(undefined)
      setTerminal(undefined)
    }
  }, [adb])

  const killProcess = useCallback(() => {
    console.log('killing shell')
    console.log(process)
    if (process && terminal) {
      terminal.write('exit\n')
      reader?.close()
      process.stderr.cancel()
      process.stdin.close()
      process.stdout.cancel()
      process.kill()
    }
  }, [process])

  return (
    <Card>
      <CardHeader>
        <CardTitle>Shell</CardTitle>
        <CardDescription>Access your device's shell using a terminal emulator</CardDescription>
      </CardHeader>
      <CardContent>
        <div className="flex items-center justify-end py-3 w-full">
          <div>
            <Button variant={'destructive'} onClick={killProcess}>
              Kill Shell
            </Button>
          </div>
        </div>
        {terminal ? (
          <ShellTerminal terminal={terminal} />
        ) : (
          <div className="w-full h-[800px] bg-slate-700 flex justify-center items-center">
            <h1>No Connection ADB</h1>
          </div>
        )}
      </CardContent>
    </Card>
  )
})

interface ShellTerminalProps {
  terminal: Terminal
}

const ShellTerminal: React.FC<ShellTerminalProps> = ({ terminal }) => {
  const shellRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    console.log(shellRef.current)
    // check if shellRef is have child remove all
    if (shellRef.current && shellRef.current.children.length > 0) {
      for (const child of shellRef.current.children) {
        shellRef.current.removeChild(child)
      }
    }

    if (terminal && shellRef.current) {
      const addon = new FitAddon()
      terminal.loadAddon(addon)
      terminal.open(shellRef.current)
      addon.fit()
    }
  }, [terminal])

  return <div className="w-full h-[800px] bg-slate-700" ref={shellRef}></div>
}
