<!-- eslint-disable @angular-eslint/template/cyclomatic-complexity, @angular-eslint/template/prefer-ngsrc -->
<main
  class="min-h-[calc(100vh-2.5rem)] bg-background px-3 py-4 text-foreground sm:px-6"
  data-testid="plugin-store-page"
>
  <header class="flex flex-col gap-3 border-b border-border pb-3 lg:flex-row lg:items-center lg:justify-between">
    <div class="flex min-w-0 items-center gap-3">
      <button
        type="button"
        (click)="goBack()"
        class="grid h-8 w-8 shrink-0 place-items-center rounded-lg border border-border text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
        title="Back to app"
      >
        <ng-icon
          name="lucideArrowLeft"
          class="h-4 w-4"
        />
      </button>

      <div class="grid h-9 w-9 shrink-0 place-items-center rounded-lg bg-primary/10 text-primary">
        <ng-icon
          name="lucideStore"
          class="h-5 w-5"
        />
      </div>

      <div class="min-w-0">
        <h1 class="truncate text-xl font-semibold leading-7">Plugin Store</h1>
        <p class="truncate text-sm text-muted-foreground">
          {{ installedCount() }} installed for {{ store.installScopeLabel() }} · {{ totalSourcePlugins() }} available · {{ sourceCount() }} sources
        </p>
      </div>
    </div>

    <div class="flex flex-wrap items-center gap-2">
      <button
        type="button"
        (click)="openManager()"
        class="inline-flex min-h-8 items-center justify-center gap-2 rounded-lg border border-border bg-card px-3 py-1.5 text-sm font-semibold transition-colors hover:bg-secondary"
      >
        <ng-icon
          name="lucideSettings"
          class="h-4 w-4"
        />
        Manage Plugins
      </button>
      <button
        type="button"
        (click)="refreshSources()"
        [disabled]="store.isLoading()"
        class="inline-flex min-h-8 items-center justify-center gap-2 rounded-lg border border-border bg-card px-3 py-1.5 text-sm font-semibold transition-colors hover:bg-secondary disabled:cursor-not-allowed disabled:opacity-55"
      >
        <ng-icon
          name="lucideRefreshCw"
          class="h-4 w-4"
          [class.animate-spin]="store.isLoading()"
        />
        Refresh
      </button>
    </div>
  </header>

  <section class="grid gap-3 py-3 lg:grid-cols-[minmax(0,1fr)_auto] lg:items-center">
    <div class="flex min-w-0 flex-col gap-2 sm:flex-row">
      <label class="relative flex min-w-0 flex-1">
        <input
          type="text"
          [(ngModel)]="newSourceUrl"
          (keyup.enter)="addSourceUrl()"
          placeholder="https://example.com/plugins.json or /home/me/plugins/source.json"
          aria-label="Plugin source manifest URL"
          class="min-h-9 w-full rounded-lg border border-border bg-secondary px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary"
        />
      </label>
      <button
        type="button"
        (click)="addSourceUrl()"
        [disabled]="!newSourceUrl.trim() || store.isLoading()"
        class="inline-flex min-h-9 items-center justify-center gap-2 rounded-lg border border-primary bg-primary px-3 py-2 text-sm font-semibold text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-55"
      >
        <ng-icon
          name="lucidePlus"
          class="h-4 w-4"
        />
        Add Source
      </button>
    </div>

    @if (sourceError()) {
      <p class="text-sm text-destructive">{{ sourceError() }}</p>
    }
  </section>

  <div
    class="grid items-start gap-3"
    [ngClass]="readme() ? 'xl:grid-cols-[minmax(13rem,17rem)_minmax(0,1fr)_minmax(24rem,38rem)]' : 'xl:grid-cols-[minmax(13rem,17rem)_minmax(0,1fr)]'"
  >
    <aside
      class="grid gap-3 xl:sticky xl:top-3"
      aria-label="Plugin sources and filters"
    >
      <section class="grid min-w-0 gap-1 rounded-lg border border-border bg-card p-3">
        <div class="mb-1 flex items-center justify-between gap-2">
          <h2 class="text-xs font-bold uppercase text-foreground">Sources</h2>
          <span class="rounded-full bg-secondary px-2 py-0.5 text-xs text-muted-foreground">{{ sourceCount() }}</span>
        </div>

        <button
          type="button"
          class="flex min-w-0 items-center justify-between gap-2 rounded-md px-2 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
          [class.bg-secondary]="selectedSourceUrl() === null"
          [class.text-foreground]="selectedSourceUrl() === null"
          (click)="selectSource(null)"
        >
          <span class="truncate">All sources</span>
          <strong class="rounded-full bg-background px-2 py-0.5 text-xs text-muted-foreground">{{ totalSourcePlugins() }}</strong>
        </button>

        @for (source of store.sources(); track source.url) {
          <div class="flex min-w-0 items-center gap-1">
            <button
              type="button"
              class="flex min-w-0 flex-1 items-center justify-between gap-2 rounded-md px-2 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
              [class.bg-secondary]="selectedSourceUrl() === source.url"
              [class.text-foreground]="selectedSourceUrl() === source.url"
              (click)="selectSource(source.url)"
            >
              <span class="truncate">{{ source.title || source.url }}</span>
              <strong class="rounded-full bg-background px-2 py-0.5 text-xs text-muted-foreground">{{ source.plugins.length }}</strong>
            </button>
            <button
              type="button"
              (click)="removeSourceUrl(source.url)"
              class="grid h-8 w-8 shrink-0 place-items-center rounded-lg border border-border text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive"
              title="Remove source"
            >
              <ng-icon
                name="lucideTrash2"
                class="h-4 w-4"
              />
            </button>
          </div>
          @if (source.error) {
            <p class="px-2 text-xs text-destructive">{{ source.error }}</p>
          }
        }

        @for (sourceUrl of pendingSourceUrls(); track sourceUrl) {
          <div class="flex min-w-0 items-center gap-1">
            <button
              type="button"
              class="flex min-w-0 flex-1 items-center justify-between gap-2 rounded-md px-2 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
              [class.bg-secondary]="selectedSourceUrl() === sourceUrl"
              [class.text-foreground]="selectedSourceUrl() === sourceUrl"
              (click)="selectSource(sourceUrl)"
            >
              <span class="truncate">{{ sourceUrl }}</span>
              <strong class="rounded-full bg-background px-2 py-0.5 text-xs text-muted-foreground">0</strong>
            </button>
            <button
              type="button"
              (click)="removeSourceUrl(sourceUrl)"
              class="grid h-8 w-8 shrink-0 place-items-center rounded-lg border border-border text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive"
              title="Remove source"
            >
              <ng-icon
                name="lucideTrash2"
                class="h-4 w-4"
              />
            </button>
          </div>
        }
      </section>

      <section class="grid min-w-0 gap-2 rounded-lg border border-border bg-card p-3">
        <div class="flex items-center justify-between gap-2">
          <h2 class="text-xs font-bold uppercase text-foreground">Filters</h2>
        </div>
        <button
          type="button"
          class="flex min-w-0 items-center justify-between gap-2 rounded-md px-2 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
          [class.bg-secondary]="showInstalledOnly()"
          [class.text-foreground]="showInstalledOnly()"
          (click)="toggleInstalledOnly()"
        >
          <span>Installed only</span>
          <strong class="rounded-full bg-background px-2 py-0.5 text-xs text-muted-foreground">{{ installedCount() }}</strong>
        </button>
      </section>

      <section class="grid min-w-0 gap-2 rounded-lg border border-border bg-card p-3">
        <div class="flex items-center justify-between gap-2">
          <h2 class="text-xs font-bold uppercase text-foreground">Install server</h2>
          <span class="rounded-full bg-secondary px-2 py-0.5 text-xs text-muted-foreground">{{ manageableServers().length }}</span>
        </div>

        @if (manageableServers().length > 0) {
          @for (server of manageableServers(); track trackServer($index, server)) {
            <button
              type="button"
              (click)="selectStoreServer(server.id)"
              class="group flex min-w-0 items-start gap-2 rounded-md border border-transparent px-2 py-2 text-left transition-colors hover:border-primary/40 hover:bg-secondary"
              [class.border-primary]="selectedStoreServerId() === server.id"
              [ngClass]="{ 'bg-primary/10': selectedStoreServerId() === server.id }"
            >
              <span
                class="mt-1 h-2 w-2 shrink-0 rounded-full bg-muted-foreground group-hover:bg-primary"
                [class.bg-primary]="selectedStoreServerId() === server.id"
              ></span>
              <span class="min-w-0">
                <span class="block truncate text-sm font-semibold text-foreground">{{ server.name }}</span>
                <span class="block truncate text-xs text-muted-foreground">{{ server.sourceUrl || 'Default endpoint' }}</span>
              </span>
            </button>
          }
        } @else {
          <p class="rounded-md border border-border bg-secondary/40 px-2 py-2 text-xs leading-5 text-muted-foreground">
            No server is available for plugin installs. Owner or Manage Server access is required.
          </p>
        }
      </section>
    </aside>

    <section
      class="grid min-w-0 gap-3 rounded-lg border border-border bg-card p-3"
      aria-label="Available plugins"
    >
      <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
        <label class="relative flex min-w-0 flex-1 sm:max-w-xl">
          <ng-icon
            name="lucideSearch"
            class="pointer-events-none absolute inset-y-0 left-3 my-auto h-4 w-4 text-muted-foreground"
          />
          <input
            type="search"
            [ngModel]="searchTerm()"
            (ngModelChange)="searchTerm.set($event)"
            placeholder="Search plugins, authors, ids"
            aria-label="Search plugins"
            class="min-h-9 w-full rounded-lg border border-border bg-secondary py-2 pl-9 pr-3 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary"
          />
        </label>

        <div class="text-sm text-muted-foreground">{{ filteredPlugins().length }} shown</div>
      </div>

      @if (actionError()) {
        <p class="rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive">{{ actionError() }}</p>
      }

      @if (readmeError()) {
        <p class="rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive">{{ readmeError() }}</p>
      }

      @if (filteredPlugins().length > 0) {
        <div class="grid gap-3">
          @for (plugin of filteredPlugins(); track trackPlugin($index, plugin)) {
            <article class="grid min-w-0 overflow-hidden rounded-lg border border-border bg-background sm:grid-cols-[5.5rem_minmax(0,1fr)]">
              <div class="grid min-h-24 place-items-center bg-secondary text-muted-foreground sm:min-h-full">
                @if (plugin.imageUrl) {
                  <img
                    [src]="plugin.imageUrl"
                    [alt]="plugin.title"
                    (error)="hideBrokenImage($event)"
                    class="h-full w-full object-cover"
                  />
                } @else {
                  <ng-icon
                    name="lucidePackage"
                    class="h-6 w-6"
                  />
                }
              </div>

              <div class="grid min-w-0 gap-2 p-3">
                <div class="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] gap-2">
                  <div class="min-w-0">
                    <h2 class="truncate text-base font-semibold leading-6">{{ plugin.title }}</h2>
                    <p class="truncate text-sm text-muted-foreground">{{ plugin.author || 'Unknown author' }} · v{{ plugin.version }}</p>
                  </div>

                  @if (getPluginInstallState(plugin) === 'updateAvailable') {
                    <span
                      class="self-start whitespace-nowrap rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-primary"
                      >Update</span
                    >
                  }
                  @if (getPluginInstallState(plugin) === 'installed') {
                    <span
                      class="self-start whitespace-nowrap rounded-full bg-emerald-600/10 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-emerald-600"
                      >Installed</span
                    >
                  }
                </div>

                <p class="line-clamp-2 min-h-10 text-sm text-muted-foreground">{{ plugin.description }}</p>

                <div class="flex min-w-0 flex-wrap items-center gap-2 text-xs text-muted-foreground">
                  <span class="max-w-full truncate rounded-full bg-secondary px-2 py-1">{{ plugin.id }}</span>
                  <span class="max-w-full truncate rounded-full bg-secondary px-2 py-1">{{ plugin.sourceTitle || plugin.sourceUrl }}</span>
                </div>

                <div class="flex flex-wrap items-center gap-2">
                  <button
                    type="button"
                    (click)="runPrimaryAction(plugin)"
                    [disabled]="isPrimaryActionDisabled(plugin)"
                    [title]="serverInstallButtonTitle(plugin)"
                    class="inline-flex min-h-8 items-center justify-center gap-2 rounded-lg border border-primary bg-primary px-3 py-1.5 text-sm font-semibold text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-55"
                    [ngClass]="{
                      'border-destructive/35':
                        getPrimaryActionLabel(plugin) === 'Uninstall' || getPrimaryActionLabel(plugin) === 'Remove from Server',
                      'bg-destructive/10': getPrimaryActionLabel(plugin) === 'Uninstall' || getPrimaryActionLabel(plugin) === 'Remove from Server'
                    }"
                    [class.text-destructive]="getPrimaryActionLabel(plugin) === 'Uninstall' || getPrimaryActionLabel(plugin) === 'Remove from Server'"
                  >
                    <ng-icon
                      [name]="primaryActionIcon(plugin)"
                      class="h-4 w-4"
                      [class.animate-spin]="isPluginBusy(plugin)"
                    />
                    {{ getPrimaryActionLabel(plugin) }}
                  </button>

                  @if (plugin.readmeUrl) {
                    <button
                      type="button"
                      (click)="loadReadme(plugin)"
                      class="inline-flex min-h-8 items-center justify-center rounded-lg px-3 py-1.5 text-sm font-semibold text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
                      title="Load readme"
                    >
                      {{ isReadmeLoading(plugin) ? 'Loading' : 'Readme' }}
                    </button>
                  }

                  @if (plugin.githubUrl) {
                    <button
                      type="button"
                      (click)="openExternal(plugin.githubUrl)"
                      class="grid h-8 w-8 place-items-center rounded-lg border border-border text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
                      title="Open GitHub"
                    >
                      <ng-icon
                        name="lucideExternalLink"
                        class="h-4 w-4"
                      />
                    </button>
                  }
                </div>
              </div>
            </article>
          }
        </div>
      } @else {
        <section class="grid min-h-56 place-items-center rounded-lg border border-dashed border-border bg-background p-8 text-center">
          <div class="grid justify-items-center gap-2">
            <ng-icon
              name="lucidePackage"
              class="h-7 w-7 text-muted-foreground"
            />
            <h2 class="text-base font-semibold">No plugins found</h2>
            <p class="max-w-md text-sm text-muted-foreground">
              {{ sourceCount() ? 'Adjust filters or add another source manifest.' : 'Add a plugin source manifest URL to populate the catalog.' }}
            </p>
          </div>
        </section>
      }
    </section>

    @if (readme()) {
      <aside
        class="grid min-w-0 gap-3 rounded-lg border border-border bg-card p-3 xl:sticky xl:top-3 xl:max-h-[calc(100vh-6rem)]"
        aria-label="Plugin readme"
      >
        <div class="grid grid-cols-[minmax(0,1fr)_auto] gap-3">
          <div class="min-w-0">
            <p class="mb-1 text-xs font-bold uppercase text-primary">Readme</p>
            <h2 class="truncate text-base font-semibold">{{ readme()!.title }}</h2>
            @if (selectedReadmePlugin(); as plugin) {
              <span class="block truncate text-sm text-muted-foreground">{{ plugin.author || 'Unknown author' }} · v{{ plugin.version }}</span>
            }
          </div>
          <div class="flex items-start gap-2">
            <button
              type="button"
              (click)="toggleReadmeRawMode()"
              class="inline-flex min-h-8 items-center justify-center rounded-lg border border-border bg-secondary px-3 py-1.5 text-xs font-semibold text-foreground transition-colors hover:bg-secondary/80"
            >
              {{ readmeRawMode() ? 'Parsed' : 'Raw' }}
            </button>
            <button
              type="button"
              (click)="closeReadme()"
              class="grid h-8 w-8 place-items-center rounded-lg border border-border text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
              title="Close readme"
            >
              <ng-icon
                name="lucideX"
                class="h-4 w-4"
              />
            </button>
          </div>
        </div>

        @if (readmeRawMode()) {
          <pre class="max-h-[calc(100vh-14rem)] overflow-auto rounded-lg bg-secondary/50 p-3 text-sm whitespace-pre-wrap">{{
            readme()!.markdown
          }}</pre>
        } @else {
          <div
            class="max-h-[calc(100vh-14rem)] overflow-auto rounded-lg bg-secondary/30 p-3 text-sm leading-6 [&_a]:text-primary [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_code]:rounded [&_code]:bg-background [&_code]:px-1 [&_h1]:mb-2 [&_h1]:text-xl [&_h1]:font-semibold [&_h2]:mb-2 [&_h2]:mt-4 [&_h2]:text-lg [&_h2]:font-semibold [&_h3]:mb-1 [&_h3]:mt-3 [&_h3]:font-semibold [&_li]:ml-5 [&_ol]:list-decimal [&_p]:mb-3 [&_pre]:mb-3 [&_pre]:overflow-auto [&_pre]:rounded-lg [&_pre]:bg-background [&_pre]:p-3 [&_ul]:list-disc"
          >
            <app-chat-message-markdown [content]="readme()!.markdown" />
          </div>
        }

        <button
          type="button"
          (click)="openExternal(readme()!.url)"
          class="inline-flex min-h-8 items-center justify-center gap-2 rounded-lg border border-border bg-card px-3 py-1.5 text-sm font-semibold transition-colors hover:bg-secondary"
        >
          <ng-icon
            name="lucideExternalLink"
            class="h-4 w-4"
          />
          Open source readme
        </button>
      </aside>
    }
  </div>

  @if (serverInstallDialog(); as dialog) {
    <div
      class="fixed inset-0 z-[80] bg-black/60"
      role="presentation"
    ></div>
    <section
      class="fixed left-1/2 top-1/2 z-[81] flex max-h-[min(42rem,calc(100vh-2rem))] w-[min(34rem,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-lg border border-border bg-card text-foreground shadow-2xl"
      role="dialog"
      aria-modal="true"
      aria-labelledby="server-plugin-install-title"
    >
      <header class="flex items-start justify-between gap-4 border-b border-border p-4">
        <div class="min-w-0">
          <p class="text-sm text-muted-foreground">Server plugin install</p>
          <h2
            id="server-plugin-install-title"
            class="mt-1 truncate text-lg font-semibold"
          >
            {{ dialog.manifest.title }}
          </h2>
        </div>
        <button
          type="button"
          (click)="closeServerInstallDialog()"
          class="grid h-8 w-8 shrink-0 place-items-center rounded-lg border border-border text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
          title="Cancel install"
        >
          <ng-icon
            name="lucideX"
            class="h-4 w-4"
          />
        </button>
      </header>

      <div class="grid min-h-0 gap-4 overflow-auto p-4">
        <label class="grid gap-2">
          <span class="text-sm text-muted-foreground">Install to server</span>
          <select
            [value]="dialog.selectedServerId"
            [disabled]="serverInstallBusy()"
            (change)="selectServerInstallTarget($any($event.target).value)"
            class="min-h-9 rounded-lg border border-border bg-secondary px-3 py-2 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary disabled:cursor-not-allowed disabled:opacity-55"
          >
            @for (server of manageableServers(); track trackServer($index, server)) {
              <option [value]="server.id">{{ server.name }}</option>
            }
          </select>
        </label>

        <label class="flex items-center gap-2 rounded-lg border border-border bg-background/50 px-3 py-2 text-sm">
          <input
            type="checkbox"
            [checked]="serverInstallOptional()"
            [disabled]="serverInstallBusy()"
            (change)="serverInstallOptional.set($any($event.target).checked)"
          />
          <span>Optional for server members</span>
        </label>

        <div class="grid gap-2">
          <div class="flex items-center justify-between gap-3">
            <h3 class="text-sm font-semibold">Capabilities</h3>
            <span class="rounded-full bg-secondary px-2 py-0.5 text-xs text-muted-foreground">{{ dialog.manifest.capabilities?.length ?? 0 }}</span>
          </div>

          @if ((dialog.manifest.capabilities?.length ?? 0) > 0) {
            @for (capability of dialog.manifest.capabilities; track trackInstallCapability($index, capability)) {
              <label class="flex items-center gap-2 rounded-lg border border-border bg-background/50 px-3 py-2 text-sm">
                <input
                  type="checkbox"
                  [checked]="selectedCapabilityIds().has(capability)"
                  [disabled]="serverInstallBusy()"
                  (change)="toggleInstallCapability(capability, $any($event.target).checked)"
                />
                <span>{{ capability }}</span>
              </label>
            }
          } @else {
            <p class="text-sm text-muted-foreground">This plugin requests no capabilities.</p>
          }
        </div>

        @if (serverInstallError()) {
          <p class="rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive">{{ serverInstallError() }}</p>
        }
      </div>

      <footer class="flex justify-end gap-2 border-t border-border p-4">
        <button
          type="button"
          (click)="closeServerInstallDialog()"
          [disabled]="serverInstallBusy()"
          class="inline-flex min-h-8 items-center justify-center rounded-lg border border-border bg-card px-3 py-1.5 text-sm font-semibold transition-colors hover:bg-secondary disabled:cursor-not-allowed disabled:opacity-55"
        >
          Cancel
        </button>
        <button
          type="button"
          (click)="confirmServerInstall()"
          [disabled]="serverInstallBusy() || !dialog.selectedServerId"
          class="inline-flex min-h-8 items-center justify-center gap-2 rounded-lg border border-primary bg-primary px-3 py-1.5 text-sm font-semibold text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-55"
        >
          <ng-icon
            name="lucidePlus"
            class="h-4 w-4"
            [class.animate-spin]="serverInstallBusy()"
          />
          Install and Activate
        </button>
      </footer>
    </section>
  }
</main>
