import { useState, useEffect, useMemo, type CSSProperties } from 'react'
import { MapContainer, TileLayer, Marker, Tooltip, GeoJSON } from 'react-leaflet'
import L from 'leaflet'
import type { GeoJsonObject } from 'geojson'
import 'leaflet/dist/leaflet.css'
import { IRAN_SITES, SITE_TYPE_LABEL, type IranSite } from '@/content/iranSites'
import newsData from '@/content/iranSitesNews.json'

interface NewsItem { title: string; url: string; source: string; date: string; summary: string }
const NEWS = newsData as Record<string, NewsItem[]>

const fmtDate = (d: string) => {
  const t = Date.parse(d)
  if (Number.isNaN(t)) return ''
  return new Intl.DateTimeFormat('fa-IR', { year: 'numeric', month: 'long', day: 'numeric' }).format(new Date(t))
}

// fan out co-located sites onto a small ring so dots don't stack at country zoom.
// display-only — real lat/lng stay in the data for the card.
type Placed = IranSite & { dlat: number; dlng: number }
function spread(sites: IranSite[]): Placed[] {
  const cell = 0.25 // ~25km bucket
  const groups = new Map<string, IranSite[]>()
  for (const s of sites) {
    const k = `${Math.round(s.lat / cell)}_${Math.round(s.lng / cell)}`
    const g = groups.get(k)
    if (g) g.push(s)
    else groups.set(k, [s])
  }
  const out: Placed[] = []
  for (const arr of groups.values()) {
    if (arr.length === 1) {
      out.push({ ...arr[0], dlat: arr[0].lat, dlng: arr[0].lng })
      continue
    }
    const R = 0.18
    const cx = arr.reduce((a, s) => a + s.lat, 0) / arr.length
    const cy = arr.reduce((a, s) => a + s.lng, 0) / arr.length
    arr.forEach((s, i) => {
      const ang = (i / arr.length) * Math.PI * 2
      out.push({ ...s, dlat: cx + Math.cos(ang) * R, dlng: cy + Math.sin(ang) * R })
    })
  }
  return out
}

// breathing pulse marker — no image assets, color set per type via --c
const pulseIcon = (color: string, active: boolean) =>
  L.divIcon({
    className: '',
    html: `<span class="obs-pulse${active ? ' obs-active' : ''}" style="--c:${color}"><span class="obs-dot"></span></span>`,
    iconSize: [26, 26],
    iconAnchor: [13, 13],
  })

const GOLD = '#CD9E53'
const NAVY = '#032340'

// ponytail: hidden test page — not in router-as-nav, reachable only by URL /observe.
export default function Observe() {
  const [selected, setSelected] = useState<IranSite | null>(null)
  const [iran, setIran] = useState<GeoJsonObject | null>(null)
  const [isMobile, setIsMobile] = useState(false)
  const [sheetOpen, setSheetOpen] = useState(false) // mobile: all-news sheet collapsed by default
  const placed = useMemo(() => spread(IRAN_SITES), [])

  useEffect(() => {
    const mq = window.matchMedia('(max-width: 768px)')
    const on = () => setIsMobile(mq.matches)
    on()
    mq.addEventListener('change', on)
    return () => mq.removeEventListener('change', on)
  }, [])

  const byTime = (a: NewsItem, b: NewsItem) => (Date.parse(b.date) || 0) - (Date.parse(a.date) || 0)
  const allNews = useMemo(() => {
    const arr: (NewsItem & { siteId: string })[] = []
    for (const [id, items] of Object.entries(NEWS)) for (const it of items) arr.push({ ...it, siteId: id })
    return arr.sort(byTime)
  }, [])
  const siteName = (id: string) => IRAN_SITES.find((s) => s.id === id)?.name.fa ?? id
  const companyNews = selected ? [...(NEWS[selected.id] ?? [])].sort(byTime) : []

  const renderItems = (items: (NewsItem & { siteId?: string })[], showTag: boolean) =>
    items.length === 0 ? (
      <div style={{ padding: '24px 18px', fontSize: 14, opacity: 0.6, lineHeight: 1.8 }}>
        خبری برای این واحد یافت نشد.
      </div>
    ) : (
      items.map((it, i) => (
        <a
          key={i}
          href={it.url}
          target="_blank"
          rel="noopener noreferrer"
          style={{ display: 'block', padding: '14px 18px', borderBottom: '1px solid #f0ede6', textDecoration: 'none', color: NAVY }}
        >
          {showTag && it.siteId && (
            <div style={{ fontSize: 11, color: GOLD, fontWeight: 700, marginBottom: 4 }}>{siteName(it.siteId)}</div>
          )}
          <div style={{ fontWeight: 700, fontSize: 14, lineHeight: 1.6 }}>{it.title}</div>
          {it.summary && it.summary !== it.title && (
            <p style={{ fontSize: 12.5, lineHeight: 1.7, opacity: 0.75, margin: '6px 0 0' }}>{it.summary}</p>
          )}
          <div style={{ display: 'flex', gap: 10, marginTop: 8, fontSize: 11.5, color: '#7a7a7a' }}>
            {it.source && <span style={{ color: GOLD, fontWeight: 600 }}>{it.source}</span>}
            {fmtDate(it.date) && <span>{fmtDate(it.date)}</span>}
          </div>
        </a>
      ))
    )

  // pull Iran's border from the bundled Natural Earth geojson
  useEffect(() => {
    fetch('/globe-countries.geojson')
      .then((r) => r.json())
      .then((g) => {
        const f = g.features.find((x: any) => x.properties?.ISO_A3 === 'IRN')
        if (f) setIran(f as GeoJsonObject)
      })
      .catch(() => {})
  }, [])

  const sheetBase: CSSProperties = { background: '#fff', color: NAVY, display: 'flex', flexDirection: 'column' }
  const leftStyle: CSSProperties = isMobile
    ? { ...sheetBase, position: 'absolute', left: 0, right: 0, bottom: 0, height: sheetOpen ? '78vh' : 'auto', maxHeight: '78vh', zIndex: 1001, borderRadius: '18px 18px 0 0', boxShadow: '0 -12px 40px rgba(0,0,0,0.35)', transition: 'height 240ms ease' }
    : { ...sheetBase, position: 'absolute', top: 0, left: 0, bottom: 0, width: 360, maxWidth: '90vw', zIndex: 1001, boxShadow: '12px 0 40px rgba(0,0,0,0.35)' }
  const rightStyle: CSSProperties = isMobile
    ? { ...sheetBase, position: 'absolute', left: 0, right: 0, bottom: 0, height: '85vh', zIndex: 1002, borderRadius: '18px 18px 0 0', boxShadow: '0 -12px 40px rgba(0,0,0,0.45)' }
    : { ...sheetBase, position: 'absolute', top: 0, right: 0, bottom: 0, width: 360, maxWidth: '90vw', zIndex: 1002, boxShadow: '-12px 0 40px rgba(0,0,0,0.4)' }
  const legendStyle: CSSProperties = {
    position: 'absolute', left: '50%', transform: 'translateX(-50%)', zIndex: 1000,
    display: 'flex', gap: 14, background: 'rgba(3,35,64,0.85)', color: '#fff',
    padding: '7px 14px', borderRadius: 999, backdropFilter: 'blur(8px)', fontSize: 12.5,
    ...(isMobile ? { top: 12 } : { bottom: 20 }),
  }

  return (
    <div style={{ position: 'fixed', inset: 0, background: NAVY, direction: 'rtl' }}>
      <style>{`
        .obs-pulse { position: relative; display: block; width: 26px; height: 26px; }
        .obs-dot { position: absolute; inset: 6px; border-radius: 50%; background: var(--c); border: 1.5px solid rgba(255,255,255,0.95); box-shadow: 0 0 10px var(--c); }
        .obs-pulse::before { content: ''; position: absolute; inset: 6px; border-radius: 50%; background: var(--c); animation: obs-breathe 2.4s ease-out infinite; }
        .obs-active .obs-dot { inset: 3px; }
        .obs-active::before { animation-duration: 1.4s; }
        @keyframes obs-breathe { 0% { transform: scale(1); opacity: 0.6; } 100% { transform: scale(3.2); opacity: 0; } }
        .leaflet-container { background: #0b1a2a !important; }
      `}</style>
      <MapContainer
        center={[32.4, 53.7]}
        zoom={5}
        minZoom={4}
        maxZoom={12}
        maxBounds={[[23, 43], [40, 64]]}
        maxBoundsViscosity={1}
        style={{ width: '100%', height: '100%' }}
        zoomControl
      >
        <TileLayer
          url="https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png"
          subdomains="abcd"
          attribution="&copy; OpenStreetMap, &copy; CARTO"
          keepBuffer={8}
          updateWhenZooming={false}
        />
        {iran && (
          <GeoJSON
            data={iran}
            style={{ color: GOLD, weight: 2.5, fillColor: GOLD, fillOpacity: 0.07 }}
            interactive={false}
          />
        )}
        {placed.map((s) => {
          const c = SITE_TYPE_LABEL[s.type].color
          const active = selected?.id === s.id
          return (
            <Marker
              key={s.id}
              position={[s.dlat, s.dlng]}
              icon={pulseIcon(c, active)}
              eventHandlers={{ click: () => setSelected(s) }}
            >
              <Tooltip direction="top" offset={[0, -10]}>
                {s.name.fa}
              </Tooltip>
            </Marker>
          )
        })}
      </MapContainer>

      {/* LEFT panel — all news, always open (collapsible bottom sheet on mobile) */}
      <div style={leftStyle}>
        {isMobile && <div onClick={() => setSheetOpen((v) => !v)} style={{ width: 40, height: 4, borderRadius: 2, background: '#d8d2c6', margin: '8px auto 0', cursor: 'pointer' }} />}
        <div
          onClick={isMobile ? () => setSheetOpen((v) => !v) : undefined}
          style={{ background: NAVY, color: '#fff', padding: '14px 18px', flexShrink: 0, borderRadius: isMobile ? '14px 14px 0 0' : 0, cursor: isMobile ? 'pointer' : 'default' }}
        >
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
            <div style={{ fontWeight: 800, fontSize: 17 }}>آخرین اخبار صنعت فولاد</div>
            {isMobile && <span style={{ fontSize: 13, opacity: 0.85, transform: sheetOpen ? 'rotate(180deg)' : 'none', transition: 'transform 200ms' }}>▲</span>}
          </div>
          <div style={{ fontSize: 12, opacity: 0.8, marginTop: 4 }}>
            {isMobile ? (sheetOpen ? 'روی هر نقطه روی نقشه بزنید تا اخبار همان واحد باز شود' : `${allNews.length} خبر — برای دیدن بزنید`) : 'روی هر نقطه روی نقشه بزنید تا اخبار همان واحد در سمت راست باز شود'}
          </div>
        </div>
        {(!isMobile || sheetOpen) && (
          <div style={{ flex: 1, overflowY: 'auto', padding: '8px 0', WebkitOverflowScrolling: 'touch' }}>{renderItems(allNews, true)}</div>
        )}
      </div>

      {/* RIGHT panel — selected company (bottom sheet on mobile) */}
      {selected && (
        <div style={rightStyle}>
          {isMobile && <div style={{ width: 40, height: 4, borderRadius: 2, background: 'rgba(255,255,255,0.4)', margin: '8px auto 0' }} />}
          <div style={{ background: NAVY, color: '#fff', padding: '14px 18px', flexShrink: 0 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 8 }}>
              <div>
                <div style={{ fontWeight: 800, fontSize: 18 }}>{selected.name.fa}</div>
                <div style={{ fontSize: 12, opacity: 0.85 }}>{selected.name.en}</div>
              </div>
              <button onClick={() => setSelected(null)} style={{ background: 'transparent', border: 'none', color: '#fff', fontSize: 22, cursor: 'pointer', lineHeight: 1 }} aria-label="بستن">×</button>
            </div>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 10 }}>
              <span style={{ background: SITE_TYPE_LABEL[selected.type].color, color: '#fff', padding: '3px 10px', borderRadius: 999, fontSize: 12, fontWeight: 700 }}>{SITE_TYPE_LABEL[selected.type].fa}</span>
              <span style={{ background: 'rgba(255,255,255,0.15)', padding: '3px 10px', borderRadius: 999, fontSize: 12 }}>{selected.province}</span>
            </div>
          </div>
          <div style={{ flex: 1, overflowY: 'auto', padding: '8px 0', WebkitOverflowScrolling: 'touch' }}>{renderItems(companyNews, false)}</div>
        </div>
      )}

      {/* Legend (floating; bottom on desktop, top on mobile) */}
      <div style={legendStyle}>
        {(Object.keys(SITE_TYPE_LABEL) as (keyof typeof SITE_TYPE_LABEL)[]).map((k) => (
          <div key={k} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
            <span style={{ width: 11, height: 11, borderRadius: '50%', background: SITE_TYPE_LABEL[k].color, border: '1px solid #fff' }} />
            <span>{SITE_TYPE_LABEL[k].fa}</span>
          </div>
        ))}
      </div>
    </div>
  )
}
