/**
 * DetectionStatus - Detection rule status list/table
 * @countermeasure/web-components/security/detection-status
 */

import { type DetectionRule, type DetectionStatusConfig } from './types'
import { resolveContainer, uniqueId } from '../../primitives/utils'

export type { DetectionRule, DetectionStatusConfig } from './types'

type SortKey = 'name' | 'status' | 'severity' | 'lastTriggered' | 'triggerCount'
type SortDir = 'asc' | 'desc'

/** Status display labels */
const STATUS_LABELS: Record<DetectionRule['status'], string> = {
  active: 'Active',
  disabled: 'Disabled',
  testing: 'Testing',
  error: 'Error',
}

/** Severity order for sorting */
const SEVERITY_ORDER: Record<string, number> = {
  critical: 0,
  high: 1,
  medium: 2,
  low: 3,
  info: 4,
}

/** Status order for sorting */
const STATUS_ORDER: Record<string, number> = {
  error: 0,
  active: 1,
  testing: 2,
  disabled: 3,
}

/** Format a date to a locale string */
function formatDate(value: Date | string): string {
  const d = value instanceof Date ? value : new Date(value)
  return d.toLocaleDateString(undefined, {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  })
}

export class DetectionStatus {
  public readonly el: HTMLDivElement

  private readonly statusId: string
  private readonly showFilters: boolean
  private readonly showSearch: boolean
  private readonly ruleClickHandler: ((rule: DetectionRule) => void) | undefined
  private currentRules: DetectionRule[]
  private filteredRules: DetectionRule[]
  private sortKey: SortKey = 'name'
  private sortDir: SortDir = 'asc'
  private filterStatus: DetectionRule['status'] | 'all' = 'all'
  private filterSeverity = 'all'
  private searchQuery = ''
  private readonly boundRowHandlers: { el: HTMLElement; handler: (e: Event) => void }[] = []

  constructor(config: DetectionStatusConfig) {
    this.statusId = uniqueId('cmm-detection-status')
    this.showFilters = config.showFilters === true
    this.showSearch = config.showSearch === true
    this.ruleClickHandler = config.onRuleClick
    this.currentRules = config.rules
    this.filteredRules = [...config.rules]

    // Create root element
    this.el = document.createElement('div')
    this.el.id = this.statusId
    this.el.className = this.buildRootClassName(config.className)

    this.renderAll()

    // Mount
    const parent = resolveContainer(config.container)
    parent.appendChild(this.el)
  }

  /** Update the detection rules data */
  update(rules: DetectionRule[]): void {
    this.currentRules = rules
    this.applyFilters()
    this.renderAll()
  }

  /** Remove the element from the DOM and clean up */
  destroy(): void {
    this.cleanupHandlers()
    this.el.remove()
  }

  private renderAll(): void {
    this.cleanupHandlers()
    this.el.innerHTML = ''

    // Controls bar (search + filters)
    if (this.showSearch || this.showFilters) {
      const controls = document.createElement('div')
      controls.className = 'cmm-detection-status__controls'

      if (this.showSearch) {
        const searchInput = document.createElement('input')
        searchInput.className = 'cmm-detection-status__search'
        searchInput.type = 'text'
        searchInput.placeholder = 'Search rules...'
        searchInput.value = this.searchQuery
        searchInput.setAttribute('aria-label', 'Search detection rules')
        searchInput.addEventListener('input', () => {
          this.searchQuery = searchInput.value
          this.applyFilters()
          this.renderAll()
        })
        controls.appendChild(searchInput)
      }

      if (this.showFilters) {
        // Status filter
        const statusSelect = document.createElement('select')
        statusSelect.className = 'cmm-detection-status__filter'
        statusSelect.setAttribute('aria-label', 'Filter by status')

        const statusOptions: [string, string][] = [
          ['all', 'All Statuses'],
          ['active', 'Active'],
          ['disabled', 'Disabled'],
          ['testing', 'Testing'],
          ['error', 'Error'],
        ]
        for (const [value, label] of statusOptions) {
          const opt = document.createElement('option')
          opt.value = value
          opt.textContent = label
          if (value === this.filterStatus) {
            opt.selected = true
          }
          statusSelect.appendChild(opt)
        }
        statusSelect.addEventListener('change', () => {
          this.filterStatus = statusSelect.value as DetectionRule['status'] | 'all'
          this.applyFilters()
          this.renderAll()
        })
        controls.appendChild(statusSelect)

        // Severity filter
        const sevSelect = document.createElement('select')
        sevSelect.className = 'cmm-detection-status__filter'
        sevSelect.setAttribute('aria-label', 'Filter by severity')

        const sevOptions: [string, string][] = [
          ['all', 'All Severities'],
          ['critical', 'Critical'],
          ['high', 'High'],
          ['medium', 'Medium'],
          ['low', 'Low'],
          ['info', 'Info'],
        ]
        for (const [value, label] of sevOptions) {
          const opt = document.createElement('option')
          opt.value = value
          opt.textContent = label
          if (value === this.filterSeverity) {
            opt.selected = true
          }
          sevSelect.appendChild(opt)
        }
        sevSelect.addEventListener('change', () => {
          this.filterSeverity = sevSelect.value
          this.applyFilters()
          this.renderAll()
        })
        controls.appendChild(sevSelect)
      }

      this.el.appendChild(controls)
    }

    // Table
    const table = document.createElement('table')
    table.className = 'cmm-detection-status__table'

    // Header
    const thead = document.createElement('thead')
    const headerRow = document.createElement('tr')

    const columns: { key: SortKey; label: string }[] = [
      { key: 'name', label: 'Name' },
      { key: 'status', label: 'Status' },
      { key: 'severity', label: 'Severity' },
      { key: 'lastTriggered', label: 'Last Triggered' },
      { key: 'triggerCount', label: 'Count' },
    ]

    for (const col of columns) {
      const th = document.createElement('th')
      th.className = 'cmm-detection-status__header'
      th.textContent = col.label
      th.style.cursor = 'pointer'

      if (this.sortKey === col.key) {
        const indicator = this.sortDir === 'asc' ? ' \u2191' : ' \u2193'
        th.textContent = col.label + indicator
        th.classList.add('cmm-detection-status__header--sorted')
      }

      th.addEventListener('click', () => {
        if (this.sortKey === col.key) {
          this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc'
        } else {
          this.sortKey = col.key
          this.sortDir = 'asc'
        }
        this.applyFilters()
        this.renderAll()
      })
      headerRow.appendChild(th)
    }

    thead.appendChild(headerRow)
    table.appendChild(thead)

    // Body
    const tbody = document.createElement('tbody')

    if (this.filteredRules.length === 0) {
      const emptyRow = document.createElement('tr')
      const emptyCell = document.createElement('td')
      emptyCell.className = 'cmm-detection-status__empty'
      emptyCell.colSpan = columns.length
      emptyCell.textContent = 'No detection rules found'
      emptyRow.appendChild(emptyCell)
      tbody.appendChild(emptyRow)
    } else {
      for (const rule of this.filteredRules) {
        const tr = document.createElement('tr')
        tr.className = 'cmm-detection-status__row'

        // Name + source
        const nameTd = document.createElement('td')
        nameTd.className = 'cmm-detection-status__cell'
        const nameSpan = document.createElement('span')
        nameSpan.className = 'cmm-detection-status__name'
        nameSpan.textContent = rule.name
        nameTd.appendChild(nameSpan)
        const sourceSpan = document.createElement('span')
        sourceSpan.className = 'cmm-detection-status__source'
        sourceSpan.textContent = rule.source
        nameTd.appendChild(sourceSpan)

        // Tags
        if (rule.tags !== undefined && rule.tags.length > 0) {
          const tagsEl = document.createElement('div')
          tagsEl.className = 'cmm-detection-status__tags'
          for (const tag of rule.tags) {
            const tagEl = document.createElement('span')
            tagEl.className = 'cmm-detection-status__tag'
            tagEl.textContent = tag
            tagsEl.appendChild(tagEl)
          }
          nameTd.appendChild(tagsEl)
        }
        tr.appendChild(nameTd)

        // Status
        const statusTd = document.createElement('td')
        statusTd.className = 'cmm-detection-status__cell'
        const statusDot = document.createElement('span')
        statusDot.className = `cmm-detection-status__dot cmm-detection-status__dot--${rule.status}`
        statusDot.setAttribute('aria-hidden', 'true')
        statusTd.appendChild(statusDot)
        const statusLabel = document.createElement('span')
        statusLabel.className = 'cmm-detection-status__status-label'
        statusLabel.textContent = STATUS_LABELS[rule.status]
        statusTd.appendChild(statusLabel)
        tr.appendChild(statusTd)

        // Severity
        const sevTd = document.createElement('td')
        sevTd.className = 'cmm-detection-status__cell'
        if (rule.severity !== undefined) {
          const sevBadge = document.createElement('span')
          sevBadge.className = `cmm-detection-status__severity cmm-detection-status__severity--${rule.severity}`
          sevBadge.textContent = rule.severity.charAt(0).toUpperCase() + rule.severity.slice(1)
          sevTd.appendChild(sevBadge)
        } else {
          sevTd.textContent = '\u2014'
        }
        tr.appendChild(sevTd)

        // Last triggered
        const trigTd = document.createElement('td')
        trigTd.className = 'cmm-detection-status__cell'
        if (rule.lastTriggered !== undefined) {
          trigTd.textContent = formatDate(rule.lastTriggered)
        } else {
          trigTd.textContent = 'Never'
        }
        tr.appendChild(trigTd)

        // Trigger count
        const countTd = document.createElement('td')
        countTd.className = 'cmm-detection-status__cell'
        countTd.textContent = rule.triggerCount !== undefined ? String(rule.triggerCount) : '0'
        tr.appendChild(countTd)

        // Row click
        if (this.ruleClickHandler !== undefined) {
          tr.style.cursor = 'pointer'
          const handler = (e: Event) => {
            e.stopPropagation()
            if (this.ruleClickHandler !== undefined) {
              this.ruleClickHandler(rule)
            }
          }
          tr.addEventListener('click', handler)
          this.boundRowHandlers.push({ el: tr, handler })
        }

        tbody.appendChild(tr)
      }
    }

    table.appendChild(tbody)
    this.el.appendChild(table)
  }

  private applyFilters(): void {
    let rules = [...this.currentRules]

    // Filter by status
    if (this.filterStatus !== 'all') {
      const status = this.filterStatus
      rules = rules.filter(r => r.status === status)
    }

    // Filter by severity
    if (this.filterSeverity !== 'all') {
      const sev = this.filterSeverity
      rules = rules.filter(r => r.severity === sev)
    }

    // Filter by search
    if (this.searchQuery.length > 0) {
      const q = this.searchQuery.toLowerCase()
      rules = rules.filter(
        r => r.name.toLowerCase().includes(q) || r.source.toLowerCase().includes(q)
      )
    }

    // Sort
    rules.sort((a, b) => {
      let result = 0
      switch (this.sortKey) {
        case 'name':
          result = a.name.localeCompare(b.name)
          break
        case 'status': {
          const aOrder = STATUS_ORDER[a.status] ?? 99
          const bOrder = STATUS_ORDER[b.status] ?? 99
          result = aOrder - bOrder
          break
        }
        case 'severity': {
          const aOrder = a.severity !== undefined ? (SEVERITY_ORDER[a.severity] ?? 99) : 99
          const bOrder = b.severity !== undefined ? (SEVERITY_ORDER[b.severity] ?? 99) : 99
          result = aOrder - bOrder
          break
        }
        case 'lastTriggered': {
          const aTime =
            a.lastTriggered !== undefined
              ? a.lastTriggered instanceof Date
                ? a.lastTriggered.getTime()
                : new Date(a.lastTriggered).getTime()
              : 0
          const bTime =
            b.lastTriggered !== undefined
              ? b.lastTriggered instanceof Date
                ? b.lastTriggered.getTime()
                : new Date(b.lastTriggered).getTime()
              : 0
          result = aTime - bTime
          break
        }
        case 'triggerCount': {
          const aCount = a.triggerCount ?? 0
          const bCount = b.triggerCount ?? 0
          result = aCount - bCount
          break
        }
      }
      return this.sortDir === 'desc' ? -result : result
    })

    this.filteredRules = rules
  }

  private cleanupHandlers(): void {
    for (const entry of this.boundRowHandlers) {
      entry.el.removeEventListener('click', entry.handler)
    }
    this.boundRowHandlers.length = 0
  }

  private buildRootClassName(extra?: string): string {
    const classes = ['cmm-detection-status']
    if (extra) {
      classes.push(extra)
    }
    return classes.join(' ')
  }
}
