import {
  DeesElement,
  html,
  customElement,
  type TemplateResult,
  css,
  state,
  cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../../appstate.js';
import * as interfaces from '../../../dist_ts_interfaces/index.js';
import { viewHostCss } from '../shared/css.js';
import './dns-provider-form.js';
import type { DnsProviderForm } from './dns-provider-form.js';

declare global {
  interface HTMLElementTagNameMap {
    'ops-view-providers': OpsViewProviders;
  }
}

@customElement('ops-view-providers')
export class OpsViewProviders extends DeesElement {
  @state()
  accessor domainsState: appstate.IDomainsState = appstate.domainsStatePart.getState()!;

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

  async connectedCallback() {
    await super.connectedCallback();
    await appstate.domainsStatePart.dispatchAction(appstate.fetchDomainsAndProvidersAction, null);
  }

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

      .statusBadge {
        display: inline-flex;
        align-items: center;
        padding: 3px 10px;
        border-radius: 12px;
        font-size: 12px;
        font-weight: 600;
        text-transform: uppercase;
      }

      .statusBadge.ok {
        background: ${cssManager.bdTheme('#dcfce7', '#14532d')};
        color: ${cssManager.bdTheme('#166534', '#4ade80')};
      }

      .statusBadge.error {
        background: ${cssManager.bdTheme('#fef2f2', '#450a0a')};
        color: ${cssManager.bdTheme('#991b1b', '#f87171')};
      }

      .statusBadge.untested {
        background: ${cssManager.bdTheme('#f3f4f6', '#1f2937')};
        color: ${cssManager.bdTheme('#4b5563', '#9ca3af')};
      }

      .statusBadge.builtin {
        background: ${cssManager.bdTheme('#e0e7ff', '#1e1b4b')};
        color: ${cssManager.bdTheme('#3730a3', '#a5b4fc')};
      }
    `,
  ];

  public render(): TemplateResult {
    const providers = this.domainsState.providers;

    return html`
      <dees-heading level="3">DNS Providers</dees-heading>
      <div class="providersContainer">
        <dees-table
          .heading1=${'Providers'}
          .heading2=${'Built-in dcrouter + external DNS provider accounts'}
          .data=${providers}
          .showColumnFilters=${true}
          .displayFunction=${(p: interfaces.data.IDnsProviderPublic) => ({
            Name: p.name,
            Type: this.providerTypeLabel(p.type),
            Status: p.builtIn
              ? html`<span class="statusBadge builtin">built-in</span>`
              : this.renderStatusBadge(p.status),
            'Last Tested': p.builtIn
              ? '—'
              : p.lastTestedAt
                ? new Date(p.lastTestedAt).toLocaleString()
                : 'never',
            Error: p.builtIn ? '—' : p.lastError || '-',
          })}
          .dataActions=${[
            {
              name: 'Add Provider',
              iconName: 'lucide:plus',
              type: ['header' as const],
              actionFunc: async () => {
                await this.showCreateDialog();
              },
            },
            {
              name: 'Refresh',
              iconName: 'lucide:rotateCw',
              type: ['header' as const],
              actionFunc: async () => {
                await appstate.domainsStatePart.dispatchAction(
                  appstate.fetchDomainsAndProvidersAction,
                  null,
                );
              },
            },
            {
              name: 'Test Connection',
              iconName: 'lucide:plug',
              type: ['inRow', 'contextmenu'] as any,
              actionRelevancyCheckFunc: (p: interfaces.data.IDnsProviderPublic) => !p.builtIn,
              actionFunc: async (actionData: any) => {
                const provider = actionData.item as interfaces.data.IDnsProviderPublic;
                await this.testProvider(provider);
              },
            },
            {
              name: 'Edit',
              iconName: 'lucide:pencil',
              type: ['inRow', 'contextmenu'] as any,
              actionRelevancyCheckFunc: (p: interfaces.data.IDnsProviderPublic) => !p.builtIn,
              actionFunc: async (actionData: any) => {
                const provider = actionData.item as interfaces.data.IDnsProviderPublic;
                await this.showEditDialog(provider);
              },
            },
            {
              name: 'Delete',
              iconName: 'lucide:trash2',
              type: ['inRow', 'contextmenu'] as any,
              actionRelevancyCheckFunc: (p: interfaces.data.IDnsProviderPublic) => !p.builtIn,
              actionFunc: async (actionData: any) => {
                const provider = actionData.item as interfaces.data.IDnsProviderPublic;
                await this.deleteProvider(provider);
              },
            },
          ]}
        ></dees-table>
      </div>
    `;
  }

  private renderStatusBadge(status: interfaces.data.TDnsProviderStatus): TemplateResult {
    return html`<span class="statusBadge ${status}">${status}</span>`;
  }

  private providerTypeLabel(type: interfaces.data.TDnsProviderType): string {
    return interfaces.data.getDnsProviderTypeDescriptor(type)?.displayName ?? type;
  }

  private async showCreateDialog() {
    const { DeesModal, DeesToast } = await import('@design.estate/dees-catalog');
    const formEl = document.createElement('dns-provider-form') as DnsProviderForm;
    DeesModal.createAndShow({
      heading: 'Add DNS Provider',
      content: html`${formEl}`,
      menuOptions: [
        { name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
        {
          name: 'Create',
          action: async (modalArg: any) => {
            const data = await formEl.collectData();
            if (!data) return;
            if (!data.name) {
              DeesToast.show({ message: 'Name is required', type: 'warning', duration: 2500 });
              return;
            }
            if (!data.credentialsTouched) {
              DeesToast.show({
                message: 'Fill in the provider credentials',
                type: 'warning',
                duration: 2500,
              });
              return;
            }
            await appstate.domainsStatePart.dispatchAction(appstate.createDnsProviderAction, {
              name: data.name,
              type: data.type,
              credentials: data.credentials,
            });
            modalArg.destroy();
          },
        },
      ],
    });
  }

  private async showEditDialog(provider: interfaces.data.IDnsProviderPublic) {
    const { DeesModal } = await import('@design.estate/dees-catalog');
    const formEl = document.createElement('dns-provider-form') as DnsProviderForm;
    formEl.providerName = provider.name;
    formEl.selectedType = provider.type;
    formEl.lockType = true;
    formEl.credentialsHint =
      'Leave credential fields blank to keep the current values. Fill them to rotate.';
    DeesModal.createAndShow({
      heading: `Edit Provider: ${provider.name}`,
      content: html`${formEl}`,
      menuOptions: [
        { name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
        {
          name: 'Save',
          action: async (modalArg: any) => {
            const data = await formEl.collectData();
            if (!data) return;
            await appstate.domainsStatePart.dispatchAction(appstate.updateDnsProviderAction, {
              id: provider.id,
              name: data.name || provider.name,
              // Only send credentials if the user actually entered something —
              // otherwise we keep the current secret untouched.
              credentials: data.credentialsTouched ? data.credentials : undefined,
            });
            modalArg.destroy();
          },
        },
      ],
    });
  }

  private async testProvider(provider: interfaces.data.IDnsProviderPublic) {
    const { DeesToast } = await import('@design.estate/dees-catalog');
    await appstate.domainsStatePart.dispatchAction(appstate.testDnsProviderAction, {
      id: provider.id,
    });
    const updated = appstate.domainsStatePart
      .getState()!
      .providers.find((p) => p.id === provider.id);
    if (updated?.status === 'ok') {
      DeesToast.show({
        message: `${provider.name}: connection OK`,
        type: 'success',
        duration: 3000,
      });
    } else {
      DeesToast.show({
        message: `${provider.name}: ${updated?.lastError || 'connection failed'}`,
        type: 'error',
        duration: 4000,
      });
    }
  }

  private async deleteProvider(provider: interfaces.data.IDnsProviderPublic) {
    const linkedDomains = this.domainsState.domains.filter((d) => d.providerId === provider.id);
    const { DeesModal } = await import('@design.estate/dees-catalog');

    const doDelete = async (force: boolean) => {
      await appstate.domainsStatePart.dispatchAction(appstate.deleteDnsProviderAction, {
        id: provider.id,
        force,
      });
    };

    if (linkedDomains.length > 0) {
      DeesModal.createAndShow({
        heading: `Provider in use`,
        content: html`
          <p>
            Provider <strong>${provider.name}</strong> is referenced by ${linkedDomains.length}
            domain(s). Deleting will also remove the imported domain(s) and their cached
            records (the records at ${provider.type} are NOT touched).
          </p>
        `,
        menuOptions: [
          { name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
          {
            name: 'Force Delete',
            action: async (modalArg: any) => {
              await doDelete(true);
              modalArg.destroy();
            },
          },
        ],
      });
    } else {
      await doDelete(false);
    }
  }
}
