import { Hype } from '@because/hype'
import { define, stylesToCSS } from '@because/forge'
import { baseStyles, initScript, theme } from '@because/toes/tools'
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
import { join } from 'path'
import type { Child } from 'hono/jsx'

const TOES_DIR = process.env.TOES_DIR ?? join(process.env.HOME!, '.toes')
const ENV_DIR = join(TOES_DIR, 'env')
const GLOBAL_ENV_PATH = join(ENV_DIR, '_global.env')

const app = new Hype({ prettyHTML: false })

const Badge = define('Badge', {
  base: 'span',
  fontSize: '11px',
  padding: '2px 6px',
  borderRadius: '3px',
  backgroundColor: theme('colors-bgSubtle'),
  color: theme('colors-textMuted'),
  fontFamily: theme('fonts-sans'),
  fontWeight: 'normal',
  marginLeft: '8px',
})

const Button = define('Button', {
  base: 'button',
  padding: '6px 12px',
  fontSize: '13px',
  borderRadius: theme('radius-md'),
  border: `1px solid ${theme('colors-border')}`,
  backgroundColor: theme('colors-bgElement'),
  color: theme('colors-text'),
  cursor: 'pointer',
  states: {
    ':hover': {
      backgroundColor: theme('colors-bgHover'),
    },
  },
})

const Container = define('Container', {
  fontFamily: theme('fonts-sans'),
  padding: '20px',
  paddingTop: 0,
  maxWidth: '800px',
  margin: '0 auto',
  color: theme('colors-text'),
})

const DangerButton = define('DangerButton', {
  base: 'button',
  padding: '6px 12px',
  fontSize: '13px',
  borderRadius: theme('radius-md'),
  border: 'none',
  backgroundColor: theme('colors-error'),
  color: 'white',
  cursor: 'pointer',
  states: {
    ':hover': {
      opacity: 0.9,
    },
  },
})

const EmptyState = define('EmptyState', {
  padding: '30px',
  textAlign: 'center',
  color: theme('colors-textMuted'),
  backgroundColor: theme('colors-bgSubtle'),
  borderRadius: theme('radius-md'),
})

const EnvActions = define('EnvActions', {
  display: 'flex',
  gap: '8px',
  flexShrink: 0,
})

const EnvItem = define('EnvItem', {
  padding: '12px 15px',
  borderBottom: `1px solid ${theme('colors-border')}`,
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'space-between',
  gap: '10px',
  states: {
    ':last-child': {
      borderBottom: 'none',
    },
  },
})

const EnvKey = define('EnvKey', {
  fontFamily: theme('fonts-mono'),
  fontSize: '14px',
  fontWeight: 'bold',
  color: theme('colors-text'),
})

const EnvList = define('EnvList', {
  listStyle: 'none',
  padding: 0,
  margin: 0,
  border: `1px solid ${theme('colors-border')}`,
  borderRadius: theme('radius-md'),
  overflow: 'hidden',
})

const EnvValue = define('EnvValue', {
  fontFamily: theme('fonts-mono'),
  fontSize: '14px',
  color: theme('colors-textMuted'),
  flex: 1,
  overflow: 'hidden',
  textOverflow: 'ellipsis',
  whiteSpace: 'nowrap',
})

const ErrorBox = define('ErrorBox', {
  color: theme('colors-error'),
  padding: '20px',
  backgroundColor: theme('colors-bgElement'),
  borderRadius: theme('radius-md'),
  margin: '20px 0',
})

const Form = define('Form', {
  base: 'form',
  display: 'flex',
  gap: '10px',
  marginTop: '15px',
  padding: '15px',
  backgroundColor: theme('colors-bgSubtle'),
  borderRadius: theme('radius-md'),
})

const Hint = define('Hint', {
  fontSize: '12px',
  color: theme('colors-textMuted'),
  marginTop: '10px',
})

const Input = define('Input', {
  base: 'input',
  flex: 1,
  padding: '8px 12px',
  fontSize: '14px',
  fontFamily: theme('fonts-mono'),
  borderRadius: theme('radius-md'),
  border: `1px solid ${theme('colors-border')}`,
  backgroundColor: theme('colors-bg'),
  color: theme('colors-text'),
  states: {
    ':focus': {
      outline: 'none',
      borderColor: theme('colors-primary'),
    },
  },
})

const Tab = define('Tab', {
  base: 'a',
  padding: '8px 16px',
  fontSize: '13px',
  fontFamily: theme('fonts-sans'),
  color: theme('colors-textMuted'),
  textDecoration: 'none',
  borderBottom: '2px solid transparent',
  cursor: 'pointer',
  states: {
    ':hover': {
      color: theme('colors-text'),
    },
  },
})

const TabActive = define('TabActive', {
  base: 'a',
  padding: '8px 16px',
  fontSize: '13px',
  fontFamily: theme('fonts-sans'),
  color: theme('colors-text'),
  textDecoration: 'none',
  borderBottom: `2px solid ${theme('colors-primary')}`,
  fontWeight: 'bold',
  cursor: 'default',
})

const TabBar = define('TabBar', {
  display: 'flex',
  gap: '4px',
  borderBottom: `1px solid ${theme('colors-border')}`,
  marginBottom: '15px',
})

interface EnvVar {
  key: string
  value: string
}

interface LayoutProps {
  title: string
  children: Child
}

const appEnvPath = (appName: string) =>
  join(ENV_DIR, `${appName}.env`)

function Layout({ title, children }: LayoutProps) {
  return (
    <html>
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>{title}</title>
        <link rel="stylesheet" href="/styles.css" />
      </head>
      <body>
        <script dangerouslySetInnerHTML={{ __html: initScript }} />
        <Container>
          {children}
        </Container>
        <script dangerouslySetInnerHTML={{ __html: clientScript }} />
      </body>
    </html>
  )
}

function ensureEnvDir() {
  if (!existsSync(ENV_DIR)) {
    mkdirSync(ENV_DIR, { recursive: true })
  }
}

function parseEnvFile(path: string): EnvVar[] {
  if (!existsSync(path)) return []

  const content = readFileSync(path, 'utf-8')
  const vars: EnvVar[] = []

  for (const line of content.split('\n')) {
    const trimmed = line.trim()
    if (!trimmed || trimmed.startsWith('#')) continue

    const eqIndex = trimmed.indexOf('=')
    if (eqIndex === -1) continue

    const key = trimmed.slice(0, eqIndex).trim()
    let value = trimmed.slice(eqIndex + 1).trim()

    // Remove surrounding quotes if present
    if ((value.startsWith('"') && value.endsWith('"')) ||
        (value.startsWith("'") && value.endsWith("'"))) {
      value = value.slice(1, -1)
    }

    if (key) vars.push({ key, value })
  }

  return vars
}

function writeEnvFile(path: string, vars: EnvVar[]) {
  ensureEnvDir()
  const content = vars.map(v => `${v.key}=${v.value}`).join('\n') + (vars.length ? '\n' : '')
  writeFileSync(path, content)
}

const clientScript = `
document.querySelectorAll('[data-reveal]').forEach(btn => {
  btn.addEventListener('click', () => {
    const valueEl = btn.closest('[data-env-item]').querySelector('[data-value]');
    const hidden = valueEl.dataset.hidden;
    if (hidden) {
      valueEl.textContent = hidden;
      valueEl.dataset.hidden = '';
      valueEl.style.whiteSpace = 'pre-wrap';
      valueEl.style.wordBreak = 'break-all';
      btn.textContent = 'Hide';
    } else {
      valueEl.dataset.hidden = valueEl.textContent;
      valueEl.textContent = '••••••••';
      valueEl.style.whiteSpace = 'nowrap';
      valueEl.style.wordBreak = '';
      btn.textContent = 'Reveal';
    }
  });
});
`

app.get('/ok', c => c.text('ok'))

app.get('/styles.css', c => c.text(baseStyles + stylesToCSS(), 200, {
  'Content-Type': 'text/css; charset=utf-8',
}))

app.get('/', async c => {
  const appName = c.req.query('app')

  if (!appName) {
    return c.html(
      <Layout title="Environment Variables">
        <ErrorBox>Please specify an app name with ?app=&lt;name&gt;</ErrorBox>
      </Layout>
    )
  }

  const tab = c.req.query('tab') === 'global' ? 'global' : 'app'
  const appUrl = `/?app=${appName}`
  const globalUrl = `/?app=${appName}&tab=global`

  if (tab === 'global') {
    const globalVars = parseEnvFile(GLOBAL_ENV_PATH)

    return c.html(
      <Layout title={`Env - Global`}>
        <TabBar>
          <Tab href={appUrl}>App</Tab>
          <TabActive href={globalUrl}>Global</TabActive>
        </TabBar>
        {globalVars.length === 0 ? (
          <EmptyState>No global environment variables</EmptyState>
        ) : (
          <EnvList>
            {globalVars.map(v => (
              <EnvItem data-env-item>
                <EnvKey>{v.key}</EnvKey>
                <EnvValue data-value data-hidden={v.value}>{'••••••••'}</EnvValue>
                <EnvActions>
                  <Button data-reveal>Reveal</Button>
                  <form method="post" action={`/delete-global?app=${appName}&key=${v.key}`} style="margin:0">
                    <DangerButton type="submit">Delete</DangerButton>
                  </form>
                </EnvActions>
              </EnvItem>
            ))}
          </EnvList>
        )}
        <Form method="POST" action={`/set-global?app=${appName}`}>
          <Input type="text" name="key" placeholder="KEY" required />
          <Input type="text" name="value" placeholder="value" required />
          <Button type="submit">Add</Button>
        </Form>
        <Hint>Global vars are available to all apps. Changes take effect on next app restart.</Hint>
      </Layout>
    )
  }

  const appVars = parseEnvFile(appEnvPath(appName))
  const globalVars = parseEnvFile(GLOBAL_ENV_PATH)
  const globalKeys = new Set(globalVars.map(v => v.key))

  return c.html(
    <Layout title={`Env - ${appName}`}>
      <TabBar>
        <TabActive href={appUrl}>App</TabActive>
        <Tab href={globalUrl}>Global</Tab>
      </TabBar>
      {appVars.length === 0 && globalKeys.size === 0 ? (
        <EmptyState>No environment variables</EmptyState>
      ) : (
        <EnvList>
          {appVars.map(v => (
            <EnvItem data-env-item>
              <EnvKey>
                {v.key}
                {globalKeys.has(v.key) && <Badge>overrides global</Badge>}
              </EnvKey>
              <EnvValue data-value data-hidden={v.value}>{'••••••••'}</EnvValue>
              <EnvActions>
                <Button data-reveal>Reveal</Button>
                <form method="post" action={`/delete?app=${appName}&key=${v.key}`} style="margin:0">
                  <DangerButton type="submit">Delete</DangerButton>
                </form>
              </EnvActions>
            </EnvItem>
          ))}
          {globalVars.filter(v => !appVars.some(a => a.key === v.key)).map(v => (
            <EnvItem data-env-item>
              <EnvKey>
                {v.key}
                <Badge>global</Badge>
              </EnvKey>
              <EnvValue data-value data-hidden={v.value}>{'••••••••'}</EnvValue>
              <EnvActions>
                <Button data-reveal>Reveal</Button>
              </EnvActions>
            </EnvItem>
          ))}
        </EnvList>
      )}
      <Form method="POST" action={`/set?app=${appName}`}>
        <Input type="text" name="key" placeholder="KEY" required />
        <Input type="text" name="value" placeholder="value" required />
        <Button type="submit">Add</Button>
      </Form>
    </Layout>
  )
})

app.post('/set', async c => {
  const appName = c.req.query('app')
  if (!appName) return c.text('Missing app', 400)

  const body = await c.req.parseBody()
  const key = String(body.key).trim().toUpperCase()
  const value = String(body.value)

  if (!key) return c.text('Missing key', 400)

  const path = appEnvPath(appName)
  const vars = parseEnvFile(path)
  const existing = vars.findIndex(v => v.key === key)

  if (existing >= 0) {
    vars[existing]!.value = value
  } else {
    vars.push({ key, value })
  }

  writeEnvFile(path, vars)
  return c.redirect(`/?app=${appName}`)
})

app.post('/delete', async c => {
  const appName = c.req.query('app')
  const key = c.req.query('key')
  if (!appName || !key) return c.text('Missing app or key', 400)

  const path = appEnvPath(appName)
  const vars = parseEnvFile(path).filter(v => v.key !== key)
  writeEnvFile(path, vars)
  return c.redirect(`/?app=${appName}`)
})

app.post('/set-global', async c => {
  const appName = c.req.query('app')
  if (!appName) return c.text('Missing app', 400)

  const body = await c.req.parseBody()
  const key = String(body.key).trim().toUpperCase()
  const value = String(body.value)

  if (!key) return c.text('Missing key', 400)

  const vars = parseEnvFile(GLOBAL_ENV_PATH)
  const existing = vars.findIndex(v => v.key === key)

  if (existing >= 0) {
    vars[existing]!.value = value
  } else {
    vars.push({ key, value })
  }

  writeEnvFile(GLOBAL_ENV_PATH, vars)
  return c.redirect(`/?app=${appName}&tab=global`)
})

app.post('/delete-global', async c => {
  const appName = c.req.query('app')
  const key = c.req.query('key')
  if (!appName || !key) return c.text('Missing app or key', 400)

  const vars = parseEnvFile(GLOBAL_ENV_PATH).filter(v => v.key !== key)
  writeEnvFile(GLOBAL_ENV_PATH, vars)
  return c.redirect(`/?app=${appName}&tab=global`)
})

export default app.defaults
