import * as appstate from '../../appstate.js';
import * as interfaces from '../../../dist_ts_interfaces/index.js';
import { viewHostCss } from '../shared/css.js';

import {
  DeesElement,
  customElement,
  html,
  state,
  css,
  cssManager,
  type TemplateResult,
} from '@design.estate/dees-element';
import { type IStatsTile } from '@design.estate/dees-catalog';

declare global {
  interface HTMLElementTagNameMap {
    'ops-view-security-blocked': OpsViewSecurityBlocked;
  }
}

@customElement('ops-view-security-blocked')
export class OpsViewSecurityBlocked extends DeesElement {
  @state()
  accessor securityPolicyState: appstate.ISecurityPolicyState = appstate.securityPolicyStatePart.getState()!;

  constructor() {
    super();
    const sub = appstate.securityPolicyStatePart
      .select((s) => s)
      .subscribe((s) => {
        this.securityPolicyState = s;
      });
    this.rxSubscriptions.push(sub);
  }

  public async connectedCallback() {
    await super.connectedCallback();
    await appstate.securityPolicyStatePart.dispatchAction(appstate.fetchSecurityPolicyAction, null);
  }

  public static styles = [
    cssManager.defaultStyles,
    viewHostCss,
    css`
      dees-statsgrid {
        margin-bottom: 32px;
      }

      .sectionStack {
        display: flex;
        flex-direction: column;
        gap: 32px;
      }

      .statusBadge {
        display: inline-flex;
        align-items: center;
        padding: 4px 8px;
        border-radius: 4px;
        font-size: 12px;
        font-weight: 500;
      }

      .statusBadge.enabled {
        background: ${cssManager.bdTheme('#e8f5e9', '#1a3a1a')};
        color: ${cssManager.bdTheme('#388e3c', '#66bb6a')};
      }

      .statusBadge.disabled {
        background: ${cssManager.bdTheme('#f5f5f5', '#2a2a2a')};
        color: ${cssManager.bdTheme('#757575', '#999')};
      }

      .typeBadge {
        display: inline-flex;
        align-items: center;
        padding: 4px 8px;
        border-radius: 999px;
        font-size: 12px;
        font-weight: 500;
        background: ${cssManager.bdTheme('#eef2ff', '#1e1b4b')};
        color: ${cssManager.bdTheme('#4338ca', '#a5b4fc')};
      }

      .errorMessage {
        padding: 12px 16px;
        border-radius: 8px;
        background: ${cssManager.bdTheme('#fef2f2', '#450a0a')};
        color: ${cssManager.bdTheme('#b91c1c', '#fca5a5')};
      }
    `,
  ];

  public render(): TemplateResult {
    const state = this.securityPolicyState;
    const activeRules = state.rules.filter((rule) => rule.enabled);
    const disabledRules = state.rules.length - activeRules.length;
    const compiledPolicy = state.compiledPolicy || { blockedIps: [], blockedCidrs: [] };

    const tiles: IStatsTile[] = [
      {
        id: 'activeRules',
        title: 'Active Rules',
        value: activeRules.length,
        type: 'number',
        icon: 'lucide:shield-check',
        color: activeRules.length > 0 ? '#ef4444' : '#22c55e',
        description: `${disabledRules} disabled`,
      },
      {
        id: 'compiledIps',
        title: 'Compiled IPs',
        value: compiledPolicy.blockedIps.length,
        type: 'number',
        icon: 'lucide:server-off',
        color: '#ef4444',
        description: 'Direct IP blocks enforced by SmartProxy',
      },
      {
        id: 'compiledCidrs',
        title: 'Compiled CIDRs',
        value: compiledPolicy.blockedCidrs.length,
        type: 'number',
        icon: 'lucide:network',
        color: '#f97316',
        description: 'Network ranges pushed to enforcement layers',
      },
      {
        id: 'intelligenceRecords',
        title: 'IP Intelligence',
        value: state.ipIntelligence.length,
        type: 'number',
        icon: 'lucide:radar',
        color: '#6366f1',
        description: 'Observed public IPs with enrichment',
      },
    ];

    return html`
      <dees-heading level="3">Security Blocking</dees-heading>

      ${state.error ? html`<div class="errorMessage">${state.error}</div>` : html``}

      <dees-statsgrid
        .tiles=${tiles}
        .minTileWidth=${200}
      ></dees-statsgrid>

      <div class="sectionStack">
        ${this.renderRulesTable()}
        ${this.renderCompiledPolicyTable()}
        ${this.renderIpIntelligenceTable()}
        ${this.renderAuditTable()}
      </div>
    `;
  }

  private renderRulesTable(): TemplateResult {
    return html`
      <dees-table
        .heading1=${'Managed Block Rules'}
        .heading2=${'Rules compiled into SmartProxy policy and remote ingress edge firewall snapshots'}
        .data=${this.securityPolicyState.rules}
        .rowKey=${'id'}
        .displayFunction=${(rule: interfaces.data.ISecurityBlockRule) => ({
          'Type': html`<span class="typeBadge">${rule.type}</span>`,
          'Value': rule.value,
          'Match': rule.type === 'organization' ? (rule.matchMode || 'contains') : '-',
          'Reason': rule.reason || '-',
          'Status': html`<span class="statusBadge ${rule.enabled ? 'enabled' : 'disabled'}">${rule.enabled ? 'Enabled' : 'Disabled'}</span>`,
          'Created': this.formatDateTime(rule.createdAt),
          'Updated': this.formatDateTime(rule.updatedAt),
        })}
        .dataActions=${this.getRuleActions()}
        searchable
        .showColumnFilters=${true}
        dataName="rule"
      ></dees-table>
    `;
  }

  private renderCompiledPolicyTable(): TemplateResult {
    const policy = this.securityPolicyState.compiledPolicy || { blockedIps: [], blockedCidrs: [] };
    const rows = [
      ...policy.blockedIps.map((value) => ({ type: 'ip', value })),
      ...policy.blockedCidrs.map((value) => ({ type: 'cidr', value })),
    ];

    return html`
      <dees-table
        .heading1=${'Compiled Enforcement Policy'}
        .heading2=${'Concrete IPs and CIDRs currently sent to SmartProxy and remote ingress'}
        .data=${rows}
        .rowKey=${'value'}
        .displayFunction=${(row: { type: string; value: string }) => ({
          'Enforcement Type': html`<span class="typeBadge">${row.type}</span>`,
          'Value': row.value,
        })}
        searchable
        .showColumnFilters=${true}
        dataName="compiled rule"
      ></dees-table>
    `;
  }

  private renderIpIntelligenceTable(): TemplateResult {
    return html`
      <dees-table
        .heading1=${'Observed IP Intelligence'}
        .heading2=${'Public IPs observed in network metrics and enriched for ASN / organization matching'}
        .data=${this.securityPolicyState.ipIntelligence}
        .rowKey=${'ipAddress'}
        .displayFunction=${(record: interfaces.data.IIpIntelligenceRecord) => ({
          'IP Address': record.ipAddress,
          'ASN': record.asn ? `AS${record.asn}` : '-',
          'ASN Org': record.asnOrg || '-',
          'Registrant Org': record.registrantOrg || '-',
          'Country': record.countryCode || record.country || '-',
          'Network Range': record.networkRange || '-',
          'Abuse Contact': record.abuseContact || '-',
          'Seen': record.seenCount,
          'Last Seen': this.formatDateTime(record.lastSeenAt),
        })}
        .dataActions=${this.getIpIntelligenceActions()}
        searchable
        .showColumnFilters=${true}
        dataName="ip intelligence record"
      ></dees-table>
    `;
  }

  private renderAuditTable(): TemplateResult {
    return html`
      <dees-table
        .heading1=${'Policy Audit'}
        .heading2=${'Recent security policy changes'}
        .data=${this.securityPolicyState.auditEvents}
        .rowKey=${'id'}
        .displayFunction=${(event: interfaces.data.ISecurityPolicyAuditEvent) => ({
          'Time': this.formatDateTime(event.createdAt),
          'Action': event.action,
          'Actor': event.actor,
          'Details': this.formatAuditDetails(event.details),
        })}
        searchable
        .showColumnFilters=${true}
        dataName="audit event"
      ></dees-table>
    `;
  }

  private getRuleActions() {
    return [
      {
        name: 'Create Rule',
        iconName: 'lucide:plus',
        type: ['header'] as any,
        actionFunc: async () => this.showRuleDialog(),
      },
      {
        name: 'Edit',
        iconName: 'lucide:pencil',
        type: ['inRow', 'contextmenu'] as any,
        actionFunc: async (actionData: any) => this.showRuleDialog(actionData.item),
      },
      {
        name: 'Enable',
        iconName: 'lucide:play',
        type: ['contextmenu'] as any,
        actionRelevancyCheckFunc: (actionData: any) => !actionData.item.enabled,
        actionFunc: async (actionData: any) => {
          const rule = actionData.item as interfaces.data.ISecurityBlockRule;
          await appstate.securityPolicyStatePart.dispatchAction(appstate.updateSecurityBlockRuleAction, {
            id: rule.id,
            enabled: true,
          });
        },
      },
      {
        name: 'Disable',
        iconName: 'lucide:pause',
        type: ['contextmenu'] as any,
        actionRelevancyCheckFunc: (actionData: any) => actionData.item.enabled,
        actionFunc: async (actionData: any) => {
          const rule = actionData.item as interfaces.data.ISecurityBlockRule;
          await appstate.securityPolicyStatePart.dispatchAction(appstate.updateSecurityBlockRuleAction, {
            id: rule.id,
            enabled: false,
          });
        },
      },
      {
        name: 'Delete',
        iconName: 'lucide:trash-2',
        type: ['contextmenu'] as any,
        actionFunc: async (actionData: any) => {
          const rule = actionData.item as interfaces.data.ISecurityBlockRule;
          if (!window.confirm(`Delete block rule ${rule.type}:${rule.value}?`)) return;
          await appstate.securityPolicyStatePart.dispatchAction(appstate.deleteSecurityBlockRuleAction, rule.id);
        },
      },
    ];
  }

  private getIpIntelligenceActions() {
    return [
      {
        name: 'Refresh Intelligence',
        iconName: 'lucide:refresh-cw',
        type: ['inRow', 'contextmenu'] as any,
        actionFunc: async (actionData: any) => {
          const record = actionData.item as interfaces.data.IIpIntelligenceRecord;
          await appstate.securityPolicyStatePart.dispatchAction(appstate.refreshIpIntelligenceAction, record.ipAddress);
        },
      },
      {
        name: 'Block IP',
        iconName: 'lucide:shield-ban',
        type: ['contextmenu'] as any,
        actionFunc: async (actionData: any) => {
          const record = actionData.item as interfaces.data.IIpIntelligenceRecord;
          await this.showRuleDialog(undefined, {
            type: 'ip',
            value: record.ipAddress,
            reason: 'Blocked from IP intelligence table',
          });
        },
      },
      {
        name: 'Block Network Range',
        iconName: 'lucide:network',
        type: ['contextmenu'] as any,
        actionRelevancyCheckFunc: (actionData: any) => Boolean(actionData.item.networkRange),
        actionFunc: async (actionData: any) => {
          const record = actionData.item as interfaces.data.IIpIntelligenceRecord;
          await this.showRuleDialog(undefined, {
            type: 'cidr',
            value: record.networkRange || '',
            reason: 'Blocked network range from IP intelligence table',
          });
        },
      },
      {
        name: 'Block ASN',
        iconName: 'lucide:radio-tower',
        type: ['contextmenu'] as any,
        actionRelevancyCheckFunc: (actionData: any) => Boolean(actionData.item.asn),
        actionFunc: async (actionData: any) => {
          const record = actionData.item as interfaces.data.IIpIntelligenceRecord;
          await this.showRuleDialog(undefined, {
            type: 'asn',
            value: String(record.asn),
            reason: 'Blocked ASN from IP intelligence table',
          });
        },
      },
      {
        name: 'Block Organization',
        iconName: 'lucide:building-2',
        type: ['contextmenu'] as any,
        actionRelevancyCheckFunc: (actionData: any) => Boolean(actionData.item.asnOrg || actionData.item.registrantOrg),
        actionFunc: async (actionData: any) => {
          const record = actionData.item as interfaces.data.IIpIntelligenceRecord;
          await this.showRuleDialog(undefined, {
            type: 'organization',
            value: record.asnOrg || record.registrantOrg || '',
            reason: 'Blocked organization from IP intelligence table',
          });
        },
      },
    ];
  }

  private async showRuleDialog(
    rule?: interfaces.data.ISecurityBlockRule,
    defaults: Partial<interfaces.data.ISecurityBlockRule> = {},
  ): Promise<void> {
    const { DeesModal } = await import('@design.estate/dees-catalog');
    const typeOptions = [
      { key: 'ip', option: 'IP address' },
      { key: 'cidr', option: 'CIDR / network range' },
      { key: 'asn', option: 'ASN' },
      { key: 'organization', option: 'Organization' },
    ];
    const matchModeOptions = [
      { key: 'contains', option: 'Organization contains value' },
      { key: 'exact', option: 'Organization exactly matches value' },
    ];
    const selectedType = rule?.type || defaults.type || 'ip';
    const selectedMatchMode = rule?.matchMode || defaults.matchMode || 'contains';

    await DeesModal.createAndShow({
      heading: rule ? `Edit Block Rule: ${rule.type}:${rule.value}` : 'Create Block Rule',
      content: html`
        <dees-form>
          ${rule ? html`` : html`
            <dees-input-dropdown
              .key=${'type'}
              .label=${'Rule Type'}
              .options=${typeOptions}
              .selectedOption=${typeOptions.find((option) => option.key === selectedType)}
            ></dees-input-dropdown>
          `}
          <dees-input-text
            .key=${'value'}
            .label=${'Value'}
            .value=${rule?.value || defaults.value || ''}
            .required=${true}
          ></dees-input-text>
          <dees-input-dropdown
            .key=${'matchMode'}
            .label=${'Organization Match Mode'}
            .description=${'Only used for organization rules'}
            .options=${matchModeOptions}
            .selectedOption=${matchModeOptions.find((option) => option.key === selectedMatchMode)}
          ></dees-input-dropdown>
          <dees-input-text
            .key=${'reason'}
            .label=${'Reason'}
            .value=${rule?.reason || defaults.reason || ''}
          ></dees-input-text>
          <dees-input-checkbox
            .key=${'enabled'}
            .label=${'Enabled'}
            .value=${rule ? rule.enabled : defaults.enabled !== false}
          ></dees-input-checkbox>
        </dees-form>
      `,
      menuOptions: [
        { name: 'Cancel', iconName: 'lucide:x', action: async (modalArg: any) => modalArg.destroy() },
        {
          name: rule ? 'Save' : 'Create',
          iconName: rule ? 'lucide:check' : 'lucide:plus',
          action: async (modalArg: any) => {
            const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
            if (!form) return;
            const data = await form.collectFormData();
            const type = (rule?.type || this.getDropdownKey(data.type)) as interfaces.data.TSecurityBlockRuleType;
            const value = String(data.value || '').trim();
            if (!type || !value) return;
            const matchMode = type === 'organization'
              ? this.getDropdownKey(data.matchMode) as interfaces.data.TSecurityBlockRuleMatchMode
              : undefined;
            const payload = {
              value,
              matchMode,
              reason: String(data.reason || '').trim() || undefined,
              enabled: data.enabled !== false,
            };
            if (rule) {
              await appstate.securityPolicyStatePart.dispatchAction(appstate.updateSecurityBlockRuleAction, {
                id: rule.id,
                ...payload,
              });
            } else {
              await appstate.securityPolicyStatePart.dispatchAction(appstate.createSecurityBlockRuleAction, {
                type,
                ...payload,
              });
            }
            await modalArg.destroy();
          },
        },
      ],
    });
  }

  private getDropdownKey(value: any): string {
    return typeof value === 'string' ? value : value?.key || '';
  }

  private formatDateTime(timestamp?: number): string {
    return timestamp ? new Date(timestamp).toLocaleString() : '-';
  }

  private formatAuditDetails(details: Record<string, unknown>): string {
    const text = JSON.stringify(details);
    return text.length > 160 ? `${text.slice(0, 157)}...` : text;
  }
}
