import React from 'react'
import styled, { keyframes } from 'styled-components'
import { Terminal } from 'react-feather'
import {
  theme,
  borders,
  colors,
  radii,
  space,
  transition,
  shadows
} from 'theme'
import Email from 'components/elements/Email'
import Box from 'components/elements/Box'
import Flex from 'components/elements/Flex'
import { parseServerTimingEntries } from 'helpers/server-timing'

const NERD_STATS_STORAGE_KEY = 'screenshot-nerd-stats'

const serializeValue = (val, indent = 2) => {
  if (val === null || val === undefined) return String(val)
  if (typeof val === 'string') return `'${val}'`
  if (typeof val !== 'object') return String(val)
  const pad = ' '.repeat(indent)
  const inner = ' '.repeat(indent + 2)
  const entries = Object.entries(val)
    .map(([k, v]) => `${inner}${k}: ${serializeValue(v, indent + 2)}`)
    .join(',\n')
  return `{\n${entries}\n${pad}}`
}

export const buildMqlQuery = (url, opts) => {
  const sanitized = { ...opts }
  if (sanitized.apiKey) sanitized.apiKey = 'MICROLINK_API_KEY'
  const inner = Object.entries(sanitized)
    .map(([k, v]) => `  ${k}: ${serializeValue(v, 2)}`)
    .join(',\n')
  return `await mql('${url}', {\n${inner}\n})`
}

const ALL_HEADER_KEYS = [
  'x-cache-status',
  'x-cache-ttl',
  'x-cache-stale-ttl',
  'x-cache',
  'x-response-time',
  'x-fetch-time',
  'x-fetch-mode',
  'x-pricing-plan',
  'x-region',
  'x-request-id',
  'x-client-ip',
  'x-timestamp',
  'x-amz-cf-pop',
  'x-amz-apigw-id',
  'x-amzn-requestid',
  'x-amzn-remapped-connection',
  'x-amzn-remapped-content-length',
  'x-amzn-remapped-date',
  'x-content-type-options',
  'x-dns-prefetch-control',
  'x-download-options',
  'x-permitted-cross-domain-policies',
  'x-robots-tag',
  'x-rate-limit-limit',
  'x-rate-limit-remaining',
  'x-rate-limit-reset',
  'x-xss-protection',
  'cf-cache-status',
  'cf-ray',
  'age',
  'cache-control',
  'etag',
  'server-timing',
  'content-encoding',
  'content-length',
  'alt-svc',
  'via',
  'server',
  'date'
]

const FULL_SECTIONS = [
  {
    label: 'Cache',
    keys: ['x-cache-status', 'x-cache-ttl', 'x-cache-stale-ttl', 'x-cache']
  },
  {
    label: 'Timing',
    keys: ['x-response-time', 'x-fetch-time', 'x-fetch-mode']
  },
  {
    label: 'Infrastructure',
    keys: [
      'x-region',
      'x-amz-cf-pop',
      'x-pricing-plan',
      'x-amz-apigw-id',
      'x-amzn-requestid',
      'x-amzn-remapped-connection',
      'x-amzn-remapped-content-length',
      'x-amzn-remapped-date',
      'cf-ray',
      'age',
      'cache-control',
      'etag',
      'server-timing',
      'content-encoding',
      'content-length',
      'alt-svc',
      'via',
      'server',
      'date'
    ]
  },
  {
    label: 'Rate Limit',
    keys: ['x-rate-limit-limit', 'x-rate-limit-remaining', 'x-rate-limit-reset']
  },
  {
    label: 'Request',
    keys: ['x-request-id', 'x-client-ip', 'x-timestamp']
  },
  {
    label: 'Security',
    keys: [
      'x-content-type-options',
      'x-dns-prefetch-control',
      'x-download-options',
      'x-permitted-cross-domain-policies',
      'x-xss-protection'
    ]
  }
]

export const extractNerdStats = headers => {
  if (!headers) return null
  const stats = {}
  let hasAny = false

  if (typeof headers.get === 'function') {
    for (const key of ALL_HEADER_KEYS) {
      const value = headers.get(key)
      if (value != null) {
        stats[key] = String(value)
        hasAny = true
      }
    }
  } else {
    const headerMap = {}
    for (const k of Object.keys(headers)) {
      headerMap[k.toLowerCase()] = headers[k]
    }
    for (const key of ALL_HEADER_KEYS) {
      const value = headerMap[key]
      if (value != null) {
        stats[key] = String(value)
        hasAny = true
      }
    }
  }

  return hasAny ? stats : null
}

const LABEL_MAP = {
  'cf-cache-status': 'status',
  'cf-ray': 'edge id',
  'cache-control': 'policy',
  'server-timing': 'timing',
  'content-encoding': 'encoding',
  'content-length': 'size',
  'alt-svc': 'http/3',
  'x-pricing-plan': 'plan',
  'x-cache-status': 'status',
  'x-cache-ttl': 'ttl',
  'x-cache-stale-ttl': 'stale ttl',
  'x-response-time': 'response time',
  'x-fetch-time': 'fetch time',
  'x-fetch-mode': 'fetch mode',
  'x-rate-limit-limit': 'limit',
  'x-rate-limit-remaining': 'remaining',
  'x-rate-limit-reset': 'reset',
  'x-request-id': 'request id',
  'x-client-ip': 'client ip',
  'x-amz-cf-pop': 'edge pop',
  'x-amz-apigw-id': 'gateway id',
  'x-amzn-requestid': 'aws request id'
}

const formatLabel = key => {
  return LABEL_MAP[key] || key.replace(/^x-/, '').replace(/-/g, ' ')
}

const formatValue = (key, value) => {
  if (key === 'x-cache-ttl') {
    const ms = Number(value)
    if (!Number.isNaN(ms)) {
      const hours = ms / 3600000
      return hours >= 1
        ? `${ms.toLocaleString()}ms (${hours.toFixed(1)}h)`
        : `${ms.toLocaleString()}ms`
    }
  }
  if (key === 'x-timestamp') {
    const ts = Number(value)
    if (!Number.isNaN(ts)) {
      try {
        return new Date(ts).toISOString().replace('T', ' ').replace('Z', ' UTC')
      } catch {
        return value
      }
    }
  }
  if (key === 'x-rate-limit-reset') {
    const ts = Number(value)
    if (!Number.isNaN(ts)) {
      try {
        const resetDate = new Date(ts * 1000)
        const diff = resetDate - Date.now()
        const mins = Math.max(0, Math.ceil(diff / 60000))
        return `${resetDate
          .toISOString()
          .replace('T', ' ')
          .replace('Z', ' UTC')} (${mins}m)`
      } catch {
        return value
      }
    }
  }
  if (key === 'age') {
    const secs = Number(value)
    if (!Number.isNaN(secs)) {
      if (secs < 60) return `${secs}s`
      if (secs < 3600) return `${Math.floor(secs / 60)}m ${secs % 60}s`
      const h = Math.floor(secs / 3600)
      const m = Math.floor((secs % 3600) / 60)
      return `${h}h ${m}m`
    }
  }
  if (key === 'content-length') {
    const bytes = Number(value)
    if (!Number.isNaN(bytes)) {
      if (bytes < 1024) return `${bytes} B`
      return `${(bytes / 1024).toFixed(1)} KB`
    }
  }
  if (key === 'server-timing') {
    const entries = parseServerTimingEntries(value).filter(
      entry => entry.dur != null
    )

    if (entries.length === 0) return value

    return (
      <span css={{ display: 'flex', flexDirection: 'column', gap: space[1] }}>
        {entries.map(({ name, dur }) => (
          <span key={name}>
            <span css={{ color: colors.green6 }}>{name}</span> {dur}
            ms
          </span>
        ))}
      </span>
    )
  }
  if (key === 'cache-control') {
    const maxAge = value.match(/max-age=(\d+)/)
    if (maxAge) {
      const secs = Number(maxAge[1])
      const h = Math.floor(secs / 3600)
      const m = Math.floor((secs % 3600) / 60)
      const human = h > 0 ? `${h}h ${m}m` : `${m}m`
      return `${value} (${human})`
    }
  }
  if (key === 'cf-ray') {
    const parts = value.split('-')
    if (parts.length === 2) return `${parts[1]} / ${parts[0]}`
  }
  if (key === 'alt-svc') {
    if (value.includes('h3=')) return 'h3 (HTTP/3)'
  }
  if (key === 'server' || key === 'via') {
    const normalized = String(value).toLowerCase()
    if (normalized.includes('cloudflare')) return 'edge'
  }
  return value
}

const fadeSlide = keyframes`
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
`

const Overlay = styled(Box)`
  position: absolute;
  inset: 0;
  z-index: 5;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  background: ${colors.black90};
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  animation: ${fadeSlide} 250ms cubic-bezier(0.4, 0, 0.2, 1) both;
  scrollbar-width: thin;
  scrollbar-color: ${colors.white20} transparent;

  &::-webkit-scrollbar {
    width: 4px;
  }
  &::-webkit-scrollbar-track {
    background: transparent;
  }
  &::-webkit-scrollbar-thumb {
    background: ${colors.white20};
    border-radius: ${radii[1]};
  }

  @media (prefers-reduced-motion: reduce) {
    animation: none;
  }
`

const QueryBlock = styled.pre`
  margin: 0;
  padding: ${space[2]} ${space[3]};
  border-radius: ${radii[3]};
  background: ${colors.black80};
  border: 1px solid ${colors.green8};
  font-size: 12px;
  line-height: 1.6;
  color: ${colors.green4};
  white-space: pre-wrap;
  word-break: break-all;
  overflow-x: auto;
`

const SectionTitle = styled.span`
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: ${colors.white70};
  padding-bottom: ${space[1]};
  display: block;
`

const Row = styled(Flex)`
  padding: 2px 0;
  gap: ${space[2]};
  align-items: baseline;
  font-size: 13px;
  line-height: 1.5;
`

const Label = styled.span`
  color: ${colors.white50};
  text-tr-nsform: capitalize;
  flex-shrink: 0;
  min-width: 90px;
  font-size: 12px;
`

const Value = styled.span`
  color: ${colors.green4};
  word-break: break-all;
  font-variant-numeric: tabular-nums;
`

const ToggleButton = styled.button`
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: ${space[1]};
  padding: ${space[2]};
  aspect-ratio: 1;
  border-radius: ${radii[3]};
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  border: 1px solid;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  font-family: inherit;
  transition: background ${transition.medium}, box-shadow ${transition.medium},
    transform ${transition.short};

  @media (prefers-reduced-motion: reduce) {
    transition: none;
  }

  background: ${({ $active }) => ($active ? colors.green0 : colors.white)};
  color: ${({ $active }) => ($active ? colors.green8 : colors.black80)};
  border-color: ${({ $active }) => ($active ? colors.green4 : colors.black10)};

  &:hover {
    transform: translateY(-1px);
    box-shadow: ${shadows[2]};
    background: ${({ $active }) => ($active ? colors.green1 : colors.black025)};
    border-color: ${({ $active }) =>
      $active ? colors.green5 : colors.black20};
  }

  &:active {
    transform: translateY(0);
  }

  &:focus-visible {
    outline: 2px solid ${colors.link};
    outline-offset: 2px;
  }
`

const NerdStatsOverlay = ({ stats, mqlQuery, responseData }) => {
  if (!stats) return null

  const sections = FULL_SECTIONS.map(section => ({
    ...section,
    entries: section.keys
      .filter(k => stats[k] != null)
      .map(k => ({
        key: k,
        label: formatLabel(k),
        value: formatValue(k, stats[k])
      }))
  })).filter(s => s.entries.length > 0)

  if (sections.length === 0) return null

  return (
    <Overlay
      css={theme({
        fontFamily: 'mono',
        p: 4
      })}
    >
      <Flex
        css={{
          flexDirection: 'column',
          gap: space[4]
        }}
      >
        {mqlQuery && (
          <Box>
            <SectionTitle
              css={{
                fontSize: '13px',
                color: colors.green4,
                paddingBottom: space[1],
                marginBottom: space[2],
                borderBottom: `${borders[1]} ${colors.white10}`
              }}
            >
              Microlink Query Language (MQL)
            </SectionTitle>
            <QueryBlock>{mqlQuery}</QueryBlock>
          </Box>
        )}
        {responseData && (
          <Box>
            <SectionTitle
              css={{
                fontSize: '13px',
                color: colors.green4,
                paddingBottom: space[1],
                marginBottom: space[2],
                borderBottom: `${borders[1]} ${colors.white10}`
              }}
            >
              Response
            </SectionTitle>
            <QueryBlock>{responseData}</QueryBlock>
          </Box>
        )}
        <SectionTitle
          css={{
            fontSize: '13px',
            color: colors.green4,
            paddingBottom: space[1],
            borderBottom: `${borders[1]} ${colors.white10}`
          }}
        >
          Headers
        </SectionTitle>
        {sections.map(section => (
          <Box key={section.label}>
            <SectionTitle css={theme({ mb: 2 })}>{section.label}</SectionTitle>
            {section.entries.map(({ key, label, value }) => (
              <Row key={key}>
                <Label>{label}</Label>
                <Value>{value}</Value>
              </Row>
            ))}
          </Box>
        ))}
        <Box
          css={{
            marginTop: space[2],
            paddingTop: '12px',
            borderTop: `${borders[1]} ${colors.white10}`,
            fontSize: '11px',
            lineHeight: 1.6,
            color: colors.white40
          }}
        >
          If you're reading this, you're our kind of people.{' '}
          <a
            href='mailto:hello@microlink.io'
            css={{
              color: colors.green5,
              textDecoration: 'none'
            }}
          >
            Say hi at <Email>hello@microlink.io</Email>
          </a>
        </Box>
      </Flex>
    </Overlay>
  )
}

export const NerdStatsToggle = ({ active, onClick }) => (
  <ToggleButton
    type='button'
    $active={active}
    onClick={onClick}
    aria-label={active ? 'Hide stats for nerds' : 'Show stats for nerds'}
    aria-pressed={active}
  >
    <Terminal size={25} aria-hidden='true' />
  </ToggleButton>
)

export { NERD_STATS_STORAGE_KEY }
export default NerdStatsOverlay
