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

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

@customElement('ops-view-gatewayclients')
export class OpsViewGatewayClients extends DeesElement {
  @state() accessor routeState: appstate.IRouteManagementState = {
    mergedRoutes: [],
    warnings: [],
    httpRedirects: [],
    apiTokens: [],
    gatewayClients: [],
    isLoading: false,
    error: null,
    lastUpdated: 0,
  };

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

    const loginSub = appstate.loginStatePart
      .select((s) => s.isLoggedIn)
      .subscribe((isLoggedIn) => {
        if (isLoggedIn) {
          appstate.routeManagementStatePart.dispatchAction(appstate.fetchGatewayClientsAction, null);
        }
      });
    this.rxSubscriptions.push(loginSub);
  }

  public static styles = [
    cssManager.defaultStyles,
    viewHostCss,
    css`
      .pill {
        display: inline-flex;
        padding: 2px 6px;
        border-radius: 3px;
        font-size: 11px;
        background: ${cssManager.bdTheme('rgba(37, 99, 235, 0.1)', 'rgba(96, 165, 250, 0.14)')};
        color: ${cssManager.bdTheme('#1d4ed8', '#93c5fd')};
        margin-right: 4px;
        margin-bottom: 2px;
      }
    `,
  ];

  public render(): TemplateResult {
    return html`
      <dees-heading level="3">Gateway Clients</dees-heading>
      <dees-table
        .heading1=${'Gateway Clients'}
        .heading2=${'Create durable clients and token credentials for Onebox, Cloudly, or custom integrations'}
        .data=${this.routeState.gatewayClients}
        .dataName=${'gateway client'}
        .searchable=${true}
        .showColumnFilters=${true}
        .displayFunction=${(client: interfaces.data.IGatewayClient) => ({
          name: client.name,
          id: client.id,
          type: client.type,
          hostnames: this.renderPills(client.hostnamePatterns),
          targets: this.renderTargets(client.allowedRouteTargets),
          tokens: client.tokenCount || 0,
          status: client.enabled ? 'Active' : 'Disabled',
        })}
        .dataActions=${[
          {
            name: 'Create Client',
            iconName: 'lucide:plus',
            type: ['header'],
            actionFunc: async () => await this.showCreateClientDialog(),
          },
          {
            name: 'Create Token',
            iconName: 'lucide:keyRound',
            type: ['inRow', 'contextmenu'] as any,
            actionFunc: async (actionData: any) => await this.showCreateTokenDialog(actionData.item),
          },
          {
            name: 'Enable',
            iconName: 'lucide:play',
            type: ['inRow', 'contextmenu'] as any,
            actionRelevancyCheckFunc: (actionData: any) => !actionData.item.enabled,
            actionFunc: async (actionData: any) => {
              await appstate.routeManagementStatePart.dispatchAction(appstate.updateGatewayClientAction, {
                id: actionData.item.id,
                enabled: true,
              });
            },
          },
          {
            name: 'Disable',
            iconName: 'lucide:pause',
            type: ['inRow', 'contextmenu'] as any,
            actionRelevancyCheckFunc: (actionData: any) => actionData.item.enabled,
            actionFunc: async (actionData: any) => {
              await appstate.routeManagementStatePart.dispatchAction(appstate.updateGatewayClientAction, {
                id: actionData.item.id,
                enabled: false,
              });
            },
          },
          {
            name: 'Delete',
            iconName: 'lucide:trash2',
            type: ['inRow', 'contextmenu'] as any,
            actionFunc: async (actionData: any) => {
              await appstate.routeManagementStatePart.dispatchAction(appstate.deleteGatewayClientAction, actionData.item.id);
            },
          },
        ]}
      ></dees-table>
    `;
  }

  private renderPills(values: string[]): TemplateResult {
    if (!values.length) return html`<span>None</span>`;
    return html`${values.map((value) => html`<span class="pill">${value}</span>`)}`;
  }

  private renderTargets(targets: interfaces.data.IGatewayClient['allowedRouteTargets']): TemplateResult {
    if (!targets.length) return html`<span>None</span>`;
    return html`${targets.map((target) => html`<span class="pill">${target.host}:${target.ports.join(',')}</span>`)}`;
  }

  private async showCreateClientDialog(): Promise<void> {
    const { DeesModal } = await import('@design.estate/dees-catalog');
    await DeesModal.createAndShow({
      heading: 'Create Gateway Client',
      content: html`
        <dees-form>
          <dees-input-text .key=${'name'} .label=${'Name'} .required=${true}></dees-input-text>
          <dees-input-text .key=${'type'} .label=${'Type'} .value=${'onebox'} .description=${'onebox, cloudly, or custom'}></dees-input-text>
          <dees-input-text .key=${'id'} .label=${'Client ID'} .description=${'Optional stable ID; generated when empty'}></dees-input-text>
          <dees-input-text .key=${'hostnamePatterns'} .label=${'Hostname Patterns'} .description=${'Comma separated, e.g. *.apps.example.com'}></dees-input-text>
          <dees-input-text .key=${'allowedRouteTarget'} .label=${'Allowed Route Target'} .description=${'Optional host:ports, e.g. onebox-smartproxy:80'}></dees-input-text>
          <dees-input-text .key=${'description'} .label=${'Description'}></dees-input-text>
        </dees-form>
      `,
      menuOptions: [
        { name: 'Cancel', iconName: 'lucide:x', action: async (modalArg: any) => await modalArg.destroy() },
        {
          name: 'Create',
          iconName: 'lucide:plus',
          action: async (modalArg: any) => {
            const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
            if (!form) return;
            const formData = await (form as any).collectFormData();
            const name = String(formData.name || '').trim();
            if (!name) return;
            await modalArg.destroy();
            await appstate.createGatewayClient({
              id: String(formData.id || '').trim() || undefined,
              type: this.normalizeClientType(String(formData.type || 'onebox')),
              name,
              description: String(formData.description || '').trim() || undefined,
              hostnamePatterns: this.parseList(String(formData.hostnamePatterns || '')),
              allowedRouteTargets: this.parseAllowedRouteTargets(String(formData.allowedRouteTarget || '')),
            });
            await appstate.routeManagementStatePart.dispatchAction(appstate.fetchGatewayClientsAction, null);
          },
        },
      ],
    });
  }

  private async showCreateTokenDialog(client: interfaces.data.IGatewayClient): Promise<void> {
    const { DeesModal } = await import('@design.estate/dees-catalog');
    await DeesModal.createAndShow({
      heading: `Create Token for ${client.name}`,
      content: html`
        <div style="color: #888; margin-bottom: 12px; font-size: 13px;">
          The token will be shown once. Configure Onebox with the dcrouter URL and this token.
        </div>
        <dees-form>
          <dees-input-text .key=${'name'} .label=${'Token Name'} .value=${`${client.name} Token`}></dees-input-text>
          <dees-input-text .key=${'expiresInDays'} .label=${'Expires in'} .description=${'Number of days; leave blank for no expiration'}></dees-input-text>
        </dees-form>
      `,
      menuOptions: [
        { name: 'Cancel', iconName: 'lucide:x', action: async (modalArg: any) => await modalArg.destroy() },
        {
          name: 'Create Token',
          iconName: 'lucide:key',
          action: async (modalArg: any) => {
            const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
            if (!form) return;
            const formData = await (form as any).collectFormData();
            const expiresInDays = formData.expiresInDays ? parseInt(formData.expiresInDays, 10) : null;
            await modalArg.destroy();
            const response = await appstate.createGatewayClientToken(
              client.id,
              String(formData.name || '').trim() || undefined,
              expiresInDays,
            );
            await appstate.routeManagementStatePart.dispatchAction(appstate.fetchGatewayClientsAction, null);
            if (response.success && response.tokenValue) {
              await DeesModal.createAndShow({
                heading: 'Gateway Client Token Created',
                content: html`
                  <p>Copy this token now. It will not be shown again.</p>
                  <div style="background: #111; padding: 12px; border-radius: 6px; margin-top: 8px;">
                    <code style="color: #0f8; word-break: break-all; font-size: 13px;">${response.tokenValue}</code>
                  </div>
                `,
                menuOptions: [
                  { name: 'Done', iconName: 'lucide:check', action: async (m: any) => await m.destroy() },
                ],
              });
            }
          },
        },
      ],
    });
  }

  private normalizeClientType(value: string): interfaces.data.IGatewayClient['type'] {
    const normalized = value.trim().toLowerCase();
    if (normalized === 'cloudly' || normalized === 'custom') return normalized;
    return 'onebox';
  }

  private parseList(value: string): string[] {
    return value.split(',').map((entry) => entry.trim()).filter(Boolean);
  }

  private parseAllowedRouteTargets(value: string): interfaces.data.IGatewayClient['allowedRouteTargets'] {
    const target = value.trim();
    if (!target.includes(':')) return [];
    const [host, portsValue] = target.split(':');
    const ports = portsValue.split(',').map((port) => Number(port.trim())).filter((port) => Number.isInteger(port));
    return host.trim() && ports.length ? [{ host: host.trim(), ports }] : [];
  }
}
