import {
  DeesElement,
  html,
  customElement,
  type TemplateResult,
  css,
  state,
  cssManager,
} from '@design.estate/dees-element';
import * as plugins from '../../plugins.js';
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';

declare global {
  interface HTMLElementTagNameMap {
    'ops-view-targetprofiles': OpsViewTargetProfiles;
  }
}

@customElement('ops-view-targetprofiles')
export class OpsViewTargetProfiles extends DeesElement {
  @state()
  accessor targetProfilesState: appstate.ITargetProfilesState = appstate.targetProfilesStatePart.getState()!;

  constructor() {
    super();
    const sub = appstate.targetProfilesStatePart.select().subscribe((newState) => {
      this.targetProfilesState = newState;
    });
    this.rxSubscriptions.push(sub);
  }

  async connectedCallback() {
    await super.connectedCallback();
    await appstate.targetProfilesStatePart.dispatchAction(appstate.fetchTargetProfilesAction, null);
  }

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

      .tagBadge {
        display: inline-flex;
        padding: 2px 8px;
        border-radius: 4px;
        font-size: 12px;
        font-weight: 500;
        background: ${cssManager.bdTheme('#eff6ff', '#172554')};
        color: ${cssManager.bdTheme('#1e40af', '#60a5fa')};
        margin-right: 4px;
        margin-bottom: 2px;
      }
    `,
  ];

  public render(): TemplateResult {
    const profiles = this.targetProfilesState.profiles;

    const statsTiles: IStatsTile[] = [
      {
        id: 'totalProfiles',
        title: 'Total Profiles',
        type: 'number',
        value: profiles.length,
        icon: 'lucide:target',
        description: 'Reusable target profiles',
        color: '#8b5cf6',
      },
    ];

    return html`
      <dees-heading level="3">Target Profiles</dees-heading>
      <div class="profilesContainer">
        <dees-statsgrid .tiles=${statsTiles}></dees-statsgrid>
        <dees-table
          .heading1=${'Target Profiles'}
          .heading2=${'Define what resources VPN clients can access'}
          .data=${profiles}
          .showColumnFilters=${true}
          .displayFunction=${(profile: interfaces.data.ITargetProfile) => ({
            Name: profile.name,
            Description: profile.description || '-',
            Domains: profile.domains?.length
              ? html`${profile.domains.map(d => html`<span class="tagBadge">${d}</span>`)}`
              : '-',
            Targets: profile.targets?.length
              ? html`${profile.targets.map(t => html`<span class="tagBadge">${t.ip}:${t.port}</span>`)}`
              : '-',
            'Route Refs': profile.routeRefs?.length
              ? html`${profile.routeRefs.map(r => html`<span class="tagBadge">${this.formatRouteRef(r)}</span>`)}`
              : '-',
            'Source-Policy Route Grants': profile.allowRoutesByClientSourceIp ? 'Yes' : 'No',
            Created: new Date(profile.createdAt).toLocaleDateString(),
          })}
          .dataActions=${[
            {
              name: 'Create Profile',
              iconName: 'lucide:plus',
              type: ['header' as const],
              actionFunc: async () => {
                await this.showCreateProfileDialog();
              },
            },
            {
              name: 'Refresh',
              iconName: 'lucide:rotateCw',
              type: ['header' as const],
              actionFunc: async () => {
                await appstate.targetProfilesStatePart.dispatchAction(appstate.fetchTargetProfilesAction, null);
              },
            },
            {
              name: 'Detail',
              iconName: 'lucide:info',
              type: ['doubleClick'] as any,
              actionFunc: async (actionData: any) => {
                const profile = actionData.item as interfaces.data.ITargetProfile;
                await this.showDetailDialog(profile);
              },
            },
            {
              name: 'Edit',
              iconName: 'lucide:pencil',
              type: ['inRow', 'contextmenu'] as any,
              actionFunc: async (actionData: any) => {
                const profile = actionData.item as interfaces.data.ITargetProfile;
                await this.showEditProfileDialog(profile);
              },
            },
            {
              name: 'Delete',
              iconName: 'lucide:trash2',
              type: ['inRow', 'contextmenu'] as any,
              actionFunc: async (actionData: any) => {
                const profile = actionData.item as interfaces.data.ITargetProfile;
                await this.deleteProfile(profile);
              },
            },
          ]}
        ></dees-table>
      </div>
    `;
  }

  private getRouteChoices() {
    const routeState = appstate.routeManagementStatePart.getState();
    const routes = routeState?.mergedRoutes || [];
    return routes
      .filter((mr) => mr.route.name && mr.id)
      .map((mr) => ({
        routeId: mr.id!,
        routeName: mr.route.name!,
        label: `${mr.route.name} (${mr.id})`,
      }));
  }

  private getRouteCandidates() {
    return this.getRouteChoices().map((route) => ({ viewKey: route.label }));
  }

  private resolveRouteRefsToLabels(routeRefs?: string[]): string[] | undefined {
    if (!routeRefs?.length) return undefined;

    const routeChoices = this.getRouteChoices();
    const routeById = new Map(routeChoices.map((route) => [route.routeId, route.label]));
    const routeByName = new Map<string, string[]>();

    for (const route of routeChoices) {
      const labels = routeByName.get(route.routeName) || [];
      labels.push(route.label);
      routeByName.set(route.routeName, labels);
    }

    return routeRefs.map((routeRef) => {
      const routeLabel = routeById.get(routeRef);
      if (routeLabel) return routeLabel;

      const labelsForName = routeByName.get(routeRef) || [];
      if (labelsForName.length === 1) return labelsForName[0];

      return routeRef;
    });
  }

  private resolveRouteLabelsToRefs(routeRefs: string[]): string[] {
    if (!routeRefs.length) return [];

    const labelToId = new Map(
      this.getRouteChoices().map((route) => [route.label, route.routeId]),
    );
    return routeRefs.map((routeRef) => labelToId.get(routeRef) || routeRef);
  }

  private formatRouteRef(routeRef: string): string {
    return this.resolveRouteRefsToLabels([routeRef])?.[0] || routeRef;
  }

  private async ensureRoutesLoaded() {
    const routeState = appstate.routeManagementStatePart.getState();
    if (!routeState?.mergedRoutes?.length) {
      await appstate.routeManagementStatePart.dispatchAction(appstate.fetchMergedRoutesAction, null);
    }
  }

  private async showCreateProfileDialog() {
    const { DeesModal } = await import('@design.estate/dees-catalog');
    await this.ensureRoutesLoaded();
    const routeCandidates = this.getRouteCandidates();

    DeesModal.createAndShow({
      heading: 'Create Target Profile',
      content: html`
        <dees-form>
          <dees-input-text .key=${'name'} .label=${'Name'} .required=${true}></dees-input-text>
          <dees-input-text .key=${'description'} .label=${'Description'}></dees-input-text>
          <dees-input-list .key=${'domains'} .label=${'Domains'} .placeholder=${'e.g. *.example.com'} .allowFreeform=${true}></dees-input-list>
          <dees-input-list .key=${'targets'} .label=${'Targets'} .description=${'Format: ip:port, e.g. 10.0.0.1:443'} .placeholder=${'e.g. 10.0.0.1:443'} .allowFreeform=${true}></dees-input-list>
          <dees-input-list .key=${'routeRefs'} .label=${'Route Refs'} .placeholder=${'Type to search routes...'} .candidates=${routeCandidates} .allowFreeform=${true}></dees-input-list>
          <dees-input-checkbox .key=${'allowRoutesByClientSourceIp'} .label=${'Allow source-policy route grants'} .description=${'Grant these VPN clients to source-policy routes; SmartProxy still checks their real connecting IP per connection'} .value=${false}></dees-input-checkbox>
        </dees-form>
      `,
      menuOptions: [
        { name: 'Cancel', iconName: 'lucide:x', action: async (modalArg: any) => modalArg.destroy() },
        {
          name: 'Create',
          iconName: 'lucide:plus',
          action: async (modalArg: any) => {
            const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
            if (!form) return;
            const data = await form.collectFormData();
            if (!data.name) return;

            const domains: string[] = Array.isArray(data.domains) ? data.domains : [];
            const targetStrings: string[] = Array.isArray(data.targets) ? data.targets : [];
            const targets = targetStrings
              .map((s: string) => {
                const lastColon = s.lastIndexOf(':');
                if (lastColon === -1) return null;
                return {
                  ip: s.substring(0, lastColon),
                  port: parseInt(s.substring(lastColon + 1), 10),
                };
              })
              .filter((t): t is { ip: string; port: number } => t !== null && !isNaN(t.port));
            const routeRefs = this.resolveRouteLabelsToRefs(
              Array.isArray(data.routeRefs) ? data.routeRefs : [],
            );

            await appstate.targetProfilesStatePart.dispatchAction(appstate.createTargetProfileAction, {
              name: String(data.name),
              description: data.description ? String(data.description) : undefined,
              domains: domains.length > 0 ? domains : undefined,
              targets: targets.length > 0 ? targets : undefined,
              routeRefs: routeRefs.length > 0 ? routeRefs : undefined,
              allowRoutesByClientSourceIp: data.allowRoutesByClientSourceIp === true,
            });
            modalArg.destroy();
          },
        },
      ],
    });
  }

  private async showEditProfileDialog(profile: interfaces.data.ITargetProfile) {
    const currentDomains = profile.domains || [];
    const currentTargets = profile.targets?.map(t => `${t.ip}:${t.port}`) || [];
    const currentRouteRefs = this.resolveRouteRefsToLabels(profile.routeRefs) || [];

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

    DeesModal.createAndShow({
      heading: `Edit Profile: ${profile.name}`,
      content: html`
        <dees-form>
          <dees-input-text .key=${'name'} .label=${'Name'} .value=${profile.name}></dees-input-text>
          <dees-input-text .key=${'description'} .label=${'Description'} .value=${profile.description || ''}></dees-input-text>
          <dees-input-list .key=${'domains'} .label=${'Domains'} .placeholder=${'e.g. *.example.com'} .allowFreeform=${true} .value=${currentDomains}></dees-input-list>
          <dees-input-list .key=${'targets'} .label=${'Targets'} .description=${'Format: ip:port, e.g. 10.0.0.1:443'} .placeholder=${'e.g. 10.0.0.1:443'} .allowFreeform=${true} .value=${currentTargets}></dees-input-list>
          <dees-input-list .key=${'routeRefs'} .label=${'Route Refs'} .placeholder=${'Type to search routes...'} .candidates=${routeCandidates} .allowFreeform=${true} .value=${currentRouteRefs}></dees-input-list>
          <dees-input-checkbox .key=${'allowRoutesByClientSourceIp'} .label=${'Allow source-policy route grants'} .description=${'Grant these VPN clients to source-policy routes; SmartProxy still checks their real connecting IP per connection'} .value=${profile.allowRoutesByClientSourceIp === true}></dees-input-checkbox>
        </dees-form>
      `,
      menuOptions: [
        { name: 'Cancel', iconName: 'lucide:x', action: async (modalArg: any) => modalArg.destroy() },
        {
          name: 'Save',
          iconName: 'lucide:check',
          action: async (modalArg: any) => {
            const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
            if (!form) return;
            const data = await form.collectFormData();

            const domains: string[] = Array.isArray(data.domains) ? data.domains : [];
            const targetStrings: string[] = Array.isArray(data.targets) ? data.targets : [];
            const targets = targetStrings
              .map((s: string) => {
                const lastColon = s.lastIndexOf(':');
                if (lastColon === -1) return null;
                return {
                  ip: s.substring(0, lastColon),
                  port: parseInt(s.substring(lastColon + 1), 10),
                };
              })
              .filter((t): t is { ip: string; port: number } => t !== null && !isNaN(t.port));
            const routeRefs = this.resolveRouteLabelsToRefs(
              Array.isArray(data.routeRefs) ? data.routeRefs : [],
            );

            await appstate.targetProfilesStatePart.dispatchAction(appstate.updateTargetProfileAction, {
              id: profile.id,
              name: String(data.name),
              description: data.description ? String(data.description) : undefined,
              domains,
              targets,
              routeRefs,
              allowRoutesByClientSourceIp: data.allowRoutesByClientSourceIp === true,
            });
            modalArg.destroy();
          },
        },
      ],
    });
  }

  private async showDetailDialog(profile: interfaces.data.ITargetProfile) {
    const { DeesModal } = await import('@design.estate/dees-catalog');

    // Fetch usage (which VPN clients reference this profile)
    let usageHtml = html`<p style="color: #9ca3af;">Loading usage...</p>`;
    try {
      const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
        interfaces.requests.IReq_GetTargetProfileUsage
      >('/typedrequest', 'getTargetProfileUsage');
      const response = await request.fire({
        identity: appstate.loginStatePart.getState()!.identity!,
        id: profile.id,
      });
      if (response.clients.length > 0) {
        usageHtml = html`
          <div style="margin-top: 8px;">
            ${response.clients.map(c => html`
              <div style="padding: 4px 0; font-size: 13px;">
                <strong>${c.clientId}</strong>${c.description ? html` - ${c.description}` : ''}
              </div>
            `)}
          </div>
        `;
      } else {
        usageHtml = html`<p style="color: #9ca3af; font-size: 13px;">No VPN clients reference this profile.</p>`;
      }
    } catch {
      usageHtml = html`<p style="color: #9ca3af;">Usage data unavailable.</p>`;
    }

    DeesModal.createAndShow({
      heading: `Target Profile: ${profile.name}`,
      content: html`
        <div style="display: flex; flex-direction: column; gap: 12px;">
          <div>
            <div style="font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};">Description</div>
            <div style="font-size: 14px; margin-top: 4px;">${profile.description || '-'}</div>
          </div>
          <div>
            <div style="font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};">Domains</div>
            <div style="font-size: 14px; margin-top: 4px;">
              ${profile.domains?.length
                ? profile.domains.map(d => html`<span class="tagBadge">${d}</span>`)
                : '-'}
            </div>
          </div>
          <div>
            <div style="font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};">Targets</div>
            <div style="font-size: 14px; margin-top: 4px;">
              ${profile.targets?.length
                ? profile.targets.map(t => html`<span class="tagBadge">${t.ip}:${t.port}</span>`)
                : '-'}
            </div>
          </div>
          <div>
            <div style="font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};">Route Refs</div>
            <div style="font-size: 14px; margin-top: 4px;">
              ${profile.routeRefs?.length
                ? profile.routeRefs.map(r => html`<span class="tagBadge">${this.formatRouteRef(r)}</span>`)
                : '-'}
            </div>
          </div>
          <div>
            <div style="font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};">Client Source IP Routes</div>
            <div style="font-size: 14px; margin-top: 4px;">${profile.allowRoutesByClientSourceIp ? 'Enabled' : 'Disabled'}</div>
          </div>
          <div>
            <div style="font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};">Created</div>
            <div style="font-size: 14px; margin-top: 4px;">${new Date(profile.createdAt).toLocaleString()} by ${profile.createdBy}</div>
          </div>
          <div>
            <div style="font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};">Updated</div>
            <div style="font-size: 14px; margin-top: 4px;">${new Date(profile.updatedAt).toLocaleString()}</div>
          </div>
          <div>
            <div style="font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};">VPN Clients Using This Profile</div>
            ${usageHtml}
          </div>
        </div>
      `,
      menuOptions: [
        { name: 'Close', iconName: 'lucide:x', action: async (m: any) => await m.destroy() },
      ],
    });
  }

  private async deleteProfile(profile: interfaces.data.ITargetProfile) {
    await appstate.targetProfilesStatePart.dispatchAction(appstate.deleteTargetProfileAction, {
      id: profile.id,
      force: false,
    });

    const currentState = appstate.targetProfilesStatePart.getState()!;
    if (currentState.error?.includes('in use')) {
      const { DeesModal } = await import('@design.estate/dees-catalog');
      DeesModal.createAndShow({
        heading: 'Profile In Use',
        content: html`<p>${currentState.error} Force delete?</p>`,
        menuOptions: [
          {
            name: 'Force Delete',
            iconName: 'lucide:trash2',
            action: async (modalArg: any) => {
              await appstate.targetProfilesStatePart.dispatchAction(appstate.deleteTargetProfileAction, {
                id: profile.id,
                force: true,
              });
              modalArg.destroy();
            },
          },
          { name: 'Cancel', iconName: 'lucide:x', action: async (modalArg: any) => modalArg.destroy() },
        ],
      });
    }
  }
}
