import * as appstate from '../appstate.js';
import * as interfaces from '../../dist_ts_interfaces/index.js';
import { viewHostCss } from './shared/css.js';
import { type IStatsTile } from '@design.estate/dees-catalog';

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

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

  @state() accessor profilesTargetsState: appstate.IProfilesTargetsState = {
    profiles: [],
    targets: [],
    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 ptSub = appstate.profilesTargetsStatePart
      .select((s) => s)
      .subscribe((ptState) => {
        this.profilesTargetsState = ptState;
      });
    this.rxSubscriptions.push(ptSub);

    // Re-fetch routes when user logs in (fixes race condition where
    // the view is created before authentication completes)
    const loginSub = appstate.loginStatePart
      .select((s) => s.isLoggedIn)
      .subscribe((isLoggedIn) => {
        if (isLoggedIn) {
          appstate.routeManagementStatePart.dispatchAction(appstate.fetchMergedRoutesAction, null);
          appstate.profilesTargetsStatePart.dispatchAction(appstate.fetchProfilesAndTargetsAction, null);
        }
      });
    this.rxSubscriptions.push(loginSub);
  }

  public static styles = [
    cssManager.defaultStyles,
    viewHostCss,
    css`
      .routesContainer {
        display: flex;
        flex-direction: column;
        gap: 24px;
      }

      .warnings-bar {
        background: ${cssManager.bdTheme('rgba(255, 170, 0, 0.08)', 'rgba(255, 170, 0, 0.1)')};
        border: 1px solid ${cssManager.bdTheme('rgba(255, 170, 0, 0.25)', 'rgba(255, 170, 0, 0.3)')};
        border-radius: 8px;
        padding: 12px 16px;
      }

      .warning-item {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 4px 0;
        font-size: 13px;
        color: ${cssManager.bdTheme('#b45309', '#fa0')};
      }

      .warning-icon {
        flex-shrink: 0;
      }

      .empty-state {
        text-align: center;
        padding: 48px 24px;
        color: ${cssManager.bdTheme('#6b7280', '#666')};
      }

      .empty-state p {
        margin: 8px 0;
      }
    `,
  ];

  public render(): TemplateResult {
    const { mergedRoutes, warnings } = this.routeState;

    const hardcodedCount = mergedRoutes.filter((mr) => mr.source === 'hardcoded').length;
    const programmaticCount = mergedRoutes.filter((mr) => mr.source === 'programmatic').length;
    const disabledCount = mergedRoutes.filter((mr) => !mr.enabled).length;

    const statsTiles: IStatsTile[] = [
      {
        id: 'totalRoutes',
        title: 'Total Routes',
        type: 'number',
        value: mergedRoutes.length,
        icon: 'lucide:route',
        description: 'All configured routes',
        color: '#3b82f6',
      },
      {
        id: 'hardcoded',
        title: 'Hardcoded',
        type: 'number',
        value: hardcodedCount,
        icon: 'lucide:lock',
        description: 'Routes from constructor config',
        color: '#8b5cf6',
      },
      {
        id: 'programmatic',
        title: 'Programmatic',
        type: 'number',
        value: programmaticCount,
        icon: 'lucide:code',
        description: 'Routes added via API',
        color: '#0ea5e9',
      },
      {
        id: 'disabled',
        title: 'Disabled',
        type: 'number',
        value: disabledCount,
        icon: 'lucide:pauseCircle',
        description: 'Currently disabled routes',
        color: disabledCount > 0 ? '#ef4444' : '#6b7280',
      },
    ];

    // Map merged routes to sz-route-list-view format
    const szRoutes = mergedRoutes.map((mr) => {
      const tags = [...(mr.route.tags || [])];
      tags.push(mr.source);
      if (!mr.enabled) tags.push('disabled');
      if (mr.overridden) tags.push('overridden');

      return {
        ...mr.route,
        enabled: mr.enabled,
        tags,
        id: mr.storedRouteId || mr.route.name || undefined,
        metadata: mr.metadata,
      };
    });

    return html`
      <ops-sectionheading>Route Management</ops-sectionheading>

      <div class="routesContainer">
        <dees-statsgrid
          .tiles=${statsTiles}
          .gridActions=${[
            {
              name: 'Add Route',
              iconName: 'lucide:plus',
              action: () => this.showCreateRouteDialog(),
            },
            {
              name: 'Refresh',
              iconName: 'lucide:refreshCw',
              action: () => this.refreshData(),
            },
          ]}
        ></dees-statsgrid>

        ${warnings.length > 0
          ? html`
              <div class="warnings-bar">
                ${warnings.map(
                  (w) => html`
                    <div class="warning-item">
                      <span class="warning-icon">&#9888;</span>
                      <span>${w.message}</span>
                    </div>
                  `,
                )}
              </div>
            `
          : ''}

        ${szRoutes.length > 0
          ? html`
              <sz-route-list-view
                .routes=${szRoutes}
                .showActionsFilter=${(route: any) => route.tags?.includes('programmatic') ?? false}
                @route-click=${(e: CustomEvent) => this.handleRouteClick(e)}
                @route-edit=${(e: CustomEvent) => this.handleRouteEdit(e)}
                @route-delete=${(e: CustomEvent) => this.handleRouteDelete(e)}
              ></sz-route-list-view>
            `
          : html`
              <div class="empty-state">
                <p>No routes configured</p>
                <p>Add a programmatic route or check your constructor configuration.</p>
              </div>
            `}
      </div>
    `;
  }

  private async handleRouteClick(e: CustomEvent) {
    const clickedRoute = e.detail;
    if (!clickedRoute) return;

    // Find the corresponding merged route
    const merged = this.routeState.mergedRoutes.find(
      (mr) => mr.route.name === clickedRoute.name,
    );
    if (!merged) return;

    const { DeesModal } = await import('@design.estate/dees-catalog');

    if (merged.source === 'hardcoded') {
      const menuOptions = merged.enabled
        ? [
            {
              name: 'Disable Route',
              iconName: 'lucide:pause',
              action: async (modalArg: any) => {
                await appstate.routeManagementStatePart.dispatchAction(
                  appstate.setRouteOverrideAction,
                  { routeName: merged.route.name!, enabled: false },
                );
                await modalArg.destroy();
              },
            },
            {
              name: 'Close',
              iconName: 'lucide:x',
              action: async (modalArg: any) => await modalArg.destroy(),
            },
          ]
        : [
            {
              name: 'Enable Route',
              iconName: 'lucide:play',
              action: async (modalArg: any) => {
                await appstate.routeManagementStatePart.dispatchAction(
                  appstate.setRouteOverrideAction,
                  { routeName: merged.route.name!, enabled: true },
                );
                await modalArg.destroy();
              },
            },
            {
              name: 'Remove Override',
              iconName: 'lucide:undo',
              action: async (modalArg: any) => {
                await appstate.routeManagementStatePart.dispatchAction(
                  appstate.removeRouteOverrideAction,
                  merged.route.name!,
                );
                await modalArg.destroy();
              },
            },
            {
              name: 'Close',
              iconName: 'lucide:x',
              action: async (modalArg: any) => await modalArg.destroy(),
            },
          ];

      await DeesModal.createAndShow({
        heading: `Route: ${merged.route.name}`,
        content: html`
          <div style="color: #ccc; padding: 8px 0;">
            <p>Source: <strong style="color: #88f;">hardcoded</strong></p>
            <p>Status: <strong>${merged.enabled ? 'Enabled' : 'Disabled (overridden)'}</strong></p>
            <p style="color: #888; font-size: 13px;">Hardcoded routes cannot be edited or deleted, but they can be disabled via an override.</p>
          </div>
        `,
        menuOptions,
      });
    } else {
      // Programmatic route
      const meta = merged.metadata;
      await DeesModal.createAndShow({
        heading: `Route: ${merged.route.name}`,
        content: html`
          <div style="color: #ccc; padding: 8px 0;">
            <p>Source: <strong style="color: #0af;">programmatic</strong></p>
            <p>Status: <strong>${merged.enabled ? 'Enabled' : 'Disabled'}</strong></p>
            <p>ID: <code style="color: #888;">${merged.storedRouteId}</code></p>
            ${meta?.securityProfileName ? html`<p>Security Profile: <strong style="color: #a78bfa;">${meta.securityProfileName}</strong></p>` : ''}
            ${meta?.networkTargetName ? html`<p>Network Target: <strong style="color: #a78bfa;">${meta.networkTargetName}</strong></p>` : ''}
          </div>
        `,
        menuOptions: [
          {
            name: merged.enabled ? 'Disable' : 'Enable',
            iconName: merged.enabled ? 'lucide:pause' : 'lucide:play',
            action: async (modalArg: any) => {
              await appstate.routeManagementStatePart.dispatchAction(
                appstate.toggleRouteAction,
                { id: merged.storedRouteId!, enabled: !merged.enabled },
              );
              await modalArg.destroy();
            },
          },
          {
            name: 'Delete',
            iconName: 'lucide:trash-2',
            action: async (modalArg: any) => {
              await appstate.routeManagementStatePart.dispatchAction(
                appstate.deleteRouteAction,
                merged.storedRouteId!,
              );
              await modalArg.destroy();
            },
          },
          {
            name: 'Close',
            iconName: 'lucide:x',
            action: async (modalArg: any) => await modalArg.destroy(),
          },
        ],
      });
    }
  }

  private async handleRouteEdit(e: CustomEvent) {
    const clickedRoute = e.detail;
    if (!clickedRoute) return;

    const merged = this.routeState.mergedRoutes.find(
      (mr) => mr.route.name === clickedRoute.name,
    );
    if (!merged || !merged.storedRouteId) return;

    this.showEditRouteDialog(merged);
  }

  private async handleRouteDelete(e: CustomEvent) {
    const clickedRoute = e.detail;
    if (!clickedRoute) return;

    const merged = this.routeState.mergedRoutes.find(
      (mr) => mr.route.name === clickedRoute.name,
    );
    if (!merged || !merged.storedRouteId) return;

    const { DeesModal } = await import('@design.estate/dees-catalog');
    await DeesModal.createAndShow({
      heading: `Delete Route: ${merged.route.name}`,
      content: html`
        <div style="color: #ccc; padding: 8px 0;">
          <p>Are you sure you want to delete this route? This action cannot be undone.</p>
        </div>
      `,
      menuOptions: [
        {
          name: 'Cancel',
          iconName: 'lucide:x',
          action: async (modalArg: any) => await modalArg.destroy(),
        },
        {
          name: 'Delete',
          iconName: 'lucide:trash-2',
          action: async (modalArg: any) => {
            await appstate.routeManagementStatePart.dispatchAction(
              appstate.deleteRouteAction,
              merged.storedRouteId!,
            );
            await modalArg.destroy();
          },
        },
      ],
    });
  }

  private async showEditRouteDialog(merged: interfaces.data.IMergedRoute) {
    const { DeesModal } = await import('@design.estate/dees-catalog');
    const profiles = this.profilesTargetsState.profiles;
    const targets = this.profilesTargetsState.targets;

    const profileOptions = [
      { key: '', option: '(none — inline security)' },
      ...profiles.map((p) => ({
        key: p.id,
        option: `${p.name}${p.description ? ' — ' + p.description : ''}`,
      })),
    ];
    const targetOptions = [
      { key: '', option: '(none — inline target)' },
      ...targets.map((t) => ({
        key: t.id,
        option: `${t.name} (${Array.isArray(t.host) ? t.host.join(',') : t.host}:${t.port})`,
      })),
    ];

    const route = merged.route;
    const currentPorts = Array.isArray(route.match.ports)
      ? route.match.ports.map((p: any) => typeof p === 'number' ? String(p) : `${p.from}-${p.to}`).join(', ')
      : String(route.match.ports);
    const currentDomains: string[] = route.match.domains
      ? (Array.isArray(route.match.domains) ? route.match.domains : [route.match.domains])
      : [];
    const firstTarget = route.action.targets?.[0];
    const currentTargetHost = firstTarget
      ? (Array.isArray(firstTarget.host) ? firstTarget.host[0] : firstTarget.host)
      : '';
    const currentTargetPort = firstTarget?.port != null ? String(firstTarget.port) : '';

    await DeesModal.createAndShow({
      heading: `Edit Route: ${route.name}`,
      content: html`
        <dees-form>
          <dees-input-text .key=${'name'} .label=${'Route Name'} .value=${route.name || ''} .required=${true}></dees-input-text>
          <dees-input-text .key=${'ports'} .label=${'Ports (comma-separated)'} .value=${currentPorts} .required=${true}></dees-input-text>
          <dees-input-list .key=${'domains'} .label=${'Domains'} .placeholder=${'Add domain...'} .value=${currentDomains}></dees-input-list>
          <dees-input-text .key=${'priority'} .label=${'Priority (higher = matched first)'} .value=${route.priority != null ? String(route.priority) : ''}></dees-input-text>
          <dees-input-dropdown .key=${'securityProfileRef'} .label=${'Security Profile'} .options=${profileOptions} .selectedOption=${profileOptions.find((o) => o.key === (merged.metadata?.securityProfileRef || '')) || null}></dees-input-dropdown>
          <dees-input-dropdown .key=${'networkTargetRef'} .label=${'Network Target'} .options=${targetOptions} .selectedOption=${targetOptions.find((o) => o.key === (merged.metadata?.networkTargetRef || '')) || null}></dees-input-dropdown>
          <dees-input-text .key=${'targetHost'} .label=${'Target Host (if no target selected)'} .value=${currentTargetHost}></dees-input-text>
          <dees-input-text .key=${'targetPort'} .label=${'Target Port (if no target selected)'} .value=${currentTargetPort}></dees-input-text>
        </dees-form>
      `,
      menuOptions: [
        {
          name: 'Cancel',
          iconName: 'lucide:x',
          action: async (modalArg: any) => await modalArg.destroy(),
        },
        {
          name: 'Save',
          iconName: 'lucide:check',
          action: async (modalArg: any) => {
            const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
            if (!form) return;
            const formData = await form.collectFormData();
            if (!formData.name || !formData.ports) return;

            const ports = formData.ports.split(',').map((p: string) => parseInt(p.trim(), 10)).filter((p: number) => !isNaN(p));
            const domains: string[] = Array.isArray(formData.domains)
              ? formData.domains.filter(Boolean)
              : [];
            const priority = formData.priority ? parseInt(formData.priority, 10) : undefined;

            const updatedRoute: any = {
              name: formData.name,
              match: {
                ports,
                ...(domains.length > 0 ? { domains } : {}),
              },
              action: {
                type: 'forward',
                targets: [
                  {
                    host: formData.targetHost || 'localhost',
                    port: parseInt(formData.targetPort, 10) || 443,
                  },
                ],
              },
              ...(priority != null && !isNaN(priority) ? { priority } : {}),
            };

            const metadata: any = {};
            const profileRefValue = formData.securityProfileRef as any;
            const profileKey = typeof profileRefValue === 'string' ? profileRefValue : profileRefValue?.key;
            if (profileKey) {
              metadata.securityProfileRef = profileKey;
            }
            const targetRefValue = formData.networkTargetRef as any;
            const targetKey = typeof targetRefValue === 'string' ? targetRefValue : targetRefValue?.key;
            if (targetKey) {
              metadata.networkTargetRef = targetKey;
            }

            await appstate.routeManagementStatePart.dispatchAction(
              appstate.updateRouteAction,
              {
                id: merged.storedRouteId!,
                route: updatedRoute,
                metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
              },
            );
            await modalArg.destroy();
          },
        },
      ],
    });
  }

  private async showCreateRouteDialog() {
    const { DeesModal } = await import('@design.estate/dees-catalog');
    const profiles = this.profilesTargetsState.profiles;
    const targets = this.profilesTargetsState.targets;

    // Build dropdown options for profiles and targets
    const profileOptions = [
      { key: '', option: '(none — inline security)' },
      ...profiles.map((p) => ({
        key: p.id,
        option: `${p.name}${p.description ? ' — ' + p.description : ''}`,
      })),
    ];
    const targetOptions = [
      { key: '', option: '(none — inline target)' },
      ...targets.map((t) => ({
        key: t.id,
        option: `${t.name} (${Array.isArray(t.host) ? t.host.join(',') : t.host}:${t.port})`,
      })),
    ];

    await DeesModal.createAndShow({
      heading: 'Add Programmatic Route',
      content: html`
        <dees-form>
          <dees-input-text .key=${'name'} .label=${'Route Name'} .required=${true}></dees-input-text>
          <dees-input-text .key=${'ports'} .label=${'Ports (comma-separated)'} .required=${true}></dees-input-text>
          <dees-input-list .key=${'domains'} .label=${'Domains'} .placeholder=${'Add domain...'}></dees-input-list>
          <dees-input-text .key=${'priority'} .label=${'Priority (higher = matched first)'}></dees-input-text>
          <dees-input-dropdown .key=${'securityProfileRef'} .label=${'Security Profile'} .options=${profileOptions}></dees-input-dropdown>
          <dees-input-dropdown .key=${'networkTargetRef'} .label=${'Network Target'} .options=${targetOptions}></dees-input-dropdown>
          <dees-input-text .key=${'targetHost'} .label=${'Target Host (if no target selected)'} .value=${'localhost'}></dees-input-text>
          <dees-input-text .key=${'targetPort'} .label=${'Target Port (if no target selected)'}></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.collectFormData();
            if (!formData.name || !formData.ports) return;

            const ports = formData.ports.split(',').map((p: string) => parseInt(p.trim(), 10)).filter((p: number) => !isNaN(p));
            const domains: string[] = Array.isArray(formData.domains)
              ? formData.domains.filter(Boolean)
              : [];
            const priority = formData.priority ? parseInt(formData.priority, 10) : undefined;

            const route: any = {
              name: formData.name,
              match: {
                ports,
                ...(domains.length > 0 ? { domains } : {}),
              },
              action: {
                type: 'forward',
                targets: [
                  {
                    host: formData.targetHost || 'localhost',
                    port: parseInt(formData.targetPort, 10) || 443,
                  },
                ],
              },
              ...(priority != null && !isNaN(priority) ? { priority } : {}),
            };

            // Build metadata if profile/target selected
            const metadata: any = {};
            const profileRefValue = formData.securityProfileRef as any;
            const profileKey = typeof profileRefValue === 'string' ? profileRefValue : profileRefValue?.key;
            if (profileKey) {
              metadata.securityProfileRef = profileKey;
            }
            const targetRefValue = formData.networkTargetRef as any;
            const targetKey = typeof targetRefValue === 'string' ? targetRefValue : targetRefValue?.key;
            if (targetKey) {
              metadata.networkTargetRef = targetKey;
            }

            await appstate.routeManagementStatePart.dispatchAction(
              appstate.createRouteAction,
              {
                route,
                metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
              },
            );
            await modalArg.destroy();
          },
        },
      ],
    });
  }

  private refreshData() {
    appstate.routeManagementStatePart.dispatchAction(appstate.fetchMergedRoutesAction, null);
  }

  async firstUpdated() {
    await appstate.routeManagementStatePart.dispatchAction(appstate.fetchMergedRoutesAction, null);
  }
}
