import Input from "@wrnexus/ui/components/input.wrn"
import Modal from "@wrnexus/ui/components/Modal.wrn"
import Toaster from "@wrnexus/ui/components/Toaster.wrn"

// Modal demo page. Route: /modal
//
// Five real-world use cases for the shared @wrnexus/ui Modal component — each
// one exercises a different combination of props (color, variant, size,
// scrollable, destructive, showFooter, confirmDisabled) instead of just
// showing the same modal five times.
//
// Notifications go through the shared <Toaster /> mounted at the bottom of
// this page. Any client expression can raise one with the runtime global —
// toast("..."), toast.success(...), toast.error(...) — so pages never
// hand-roll a status banner and never reach for a blocking alert().
page ModalPage {

  state noteText = "Remember to ship the release notes"
  state deletedNote = ""

  functions {
    function onSaveConfirmed() {
      toast.success("Changes saved", { title: "Draft published" })
    }

    function onDeleteConfirmed() {
      toast.error("Account deleted", { title: "Gone for good", duration: 6000 })
    }

    // Toast actions and component state.
    //
    // An action callback runs LONG AFTER the function that created it
    // returned, and a client function only flushes its state when its body
    // ends -- so assigning noteText straight from the callback would write to
    // a dead local and vanish. The callback dispatches an event instead, and
    // the declarative @window binding on the actions row below handles it as
    // a fresh invocation with live state. Anything that is not component
    // state (calling toast(), fetch, navigation) works from the callback
    // directly.
    function onDeleteNote() {
      deletedNote = noteText
      noteText = ""
      toast("Note deleted", {
        title: "Deleted",
        actionLabel: "Undo",
        onAction: function () {
          window.dispatchEvent(new CustomEvent("demo:restore-note"))
        },
        duration: 8000
      })
    }

    function restoreNote() {
      if (!deletedNote) {
        return
      }
      noteText = deletedNote
      deletedNote = ""
      toast.success("Note restored")
    }

    // Two actions. The second is styled destructive and keeps the toast open
    // (dismiss: false) so the choice stays on screen until it is resolved.
    function onConflict() {
      toast.warning("This note changed in another tab", {
        title: "Conflict",
        actions: [
          {
            label: "Keep mine",
            onClick: function () { toast.success("Kept your version") }
          },
          {
            label: "Discard",
            tone: "danger",
            dismiss: false,
            onClick: function () {
              window.dispatchEvent(new CustomEvent("demo:discard-note"))
            }
          }
        ],
        duration: 0
      })
    }

    function discardNote() {
      deletedNote = noteText
      noteText = ""
      toast.error("Your changes were discarded")
    }

    // Tones carry their own icon and colour, but any toast can override it.
    // The class lives in this page source, so the app Tailwind/iconify build
    // sees it and emits the rule -- a class from inside @wrnexus/ui would not
    // be scanned, which is why the packaged defaults are inline SVG.
    function onTrialNotice() {
      toast.warning("Your trial ends in 3 days", {
        title: "Heads up",
        icon: "icon-[lucide--hourglass]",
        actionLabel: "Upgrade",
        duration: 6000
      })
    }

    function onTermsConfirmed() {
      toast.success("Thanks, you are all set")
    }

    // The invite form is a real <form data-schema="invite">, so
    // @wrnexus/validation owns the rules: it validates on input/blur/submit
    // against app/schemas/invite.ts, writes each message into the
    // [data-error] slot the Input renders, and only then POSTs to /api/invite — which parses
    // the very same schema server-side. These two handlers just react to the
    // outcome events the validator emits.
    function onInviteSent(event) {
      toast.success("Invite sent to " + event.detail.email, { title: "Invitation" })
      // Close the modal the form lives in. The event bubbles from the form up
      // to the Modal root, which listens for it -- so the page never needs a
      // handle on the modal or a way to reach its internal state.
      event.target.dispatchEvent(
        new CustomEvent("wrnexus:modal:close", { bubbles: true })
      )
    }

    function onInviteFailed(event) {
      toast.error(event.detail.message || "Could not send the invite", {
        title: "Invite failed"
      })
    }
  }

  style {
    .modal-demo-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
      gap: 1rem;
      margin-top: 1.5rem;
    }

    .modal-demo-card {
      display: flex;
      flex-direction: column;
      gap: 0.6rem;
      padding: 1.1rem;
      background: var(--wire-color-surface-raised);
      border: 1px solid var(--wire-color-border);
      border-radius: 1rem;
    }

    /*
     * Direct children only. A modal mounts *inside* its card, and its panel is
     * position: fixed but still a DOM descendant -- so a plain
     * `.modal-demo-card p` also styles the copy inside the open modal, which
     * repainted the destructive modal body muted grey on its red panel. The
     * card is describing its own blurb here, not everything a component it
     * hosts happens to render.
     */
    .modal-demo-card > h2 {
      margin: 0;
      font-size: 0.95rem;
    }

    .modal-demo-card > p {
      margin: 0;
      color: var(--wire-color-text-muted);
      font-size: 0.82rem;
      line-height: 1.5;
    }

    .modal-demo-form {
      display: grid;
      gap: 0.9rem;
    }

    .modal-demo-form-error {
      margin: 0;
      color: var(--wire-color-danger);
      font-size: 0.8rem;
    }

    .modal-demo-form-error:empty {
      display: none;
    }

    .modal-demo-submit {
      appearance: none;
      min-height: 2.55rem;
      padding: 0.65rem 1rem;
      color: var(--wire-color-secondary-contrast);
      background: var(--wire-color-secondary);
      border: 0;
      border-radius: 0.78rem;
      font: inherit;
      font-size: 0.83rem;
      font-weight: 650;
      cursor: pointer;
    }

    .modal-demo-toast-demos {
      display: flex;
      align-items: center;
      flex-wrap: wrap;
      gap: 0.5rem;
      margin-top: 1.75rem;
      color: var(--wire-color-text-muted);
      font-size: 0.82rem;
    }

    .modal-demo-note {
      color: var(--wire-color-text-muted);
    }

    .modal-demo-note em {
      color: var(--wire-color-text);
      font-style: normal;
    }

    .modal-demo-toast-demos button {
      appearance: none;
      padding: 0.4rem 0.7rem;
      color: var(--wire-color-text);
      background: var(--wire-color-surface-raised);
      border: 1px solid var(--wire-color-border);
      border-radius: 0.6rem;
      font: inherit;
      font-size: 0.78rem;
      cursor: pointer;
    }

    .modal-demo-submit:disabled {
      opacity: 0.6;
      cursor: not-allowed;
    }

    .modal-demo-terms {
      max-height: 12rem;
      overflow-y: auto;
      padding-right: 0.5rem;
      color: var(--wire-color-text-muted);
      font-size: 0.85rem;
      line-height: 1.6;
    }
  }

  view {
    <h1>Modal</h1>
    <p>
      Five common use cases for the shared <code>@wrnexus/ui</code>
      <code>Modal</code> component — themed, accessible, and responsive out
      of the box.
    </p>

    <div class="modal-demo-grid">

      <!-- 1. Info-only modal: no footer, dismiss via close button/backdrop/Escape -->
      <div class="modal-demo-card">
        <h2>Info modal</h2>
        <p>No footer, no actions — just content you dismiss.</p>
        <Modal
          title="What's new"
          description="Release notes for this build."
          triggerLabel="View release notes"
          color="info"
          variant="soft"
          size="sm"
          showFooter={false}
        >
          <p>
            This release adds the shared <code>@wrnexus/ui</code>
            <code>Modal</code> component to every app, fully themed to your
            palette and dark/light mode.
          </p>
        </Modal>
      </div>

      <!-- 2. Standard confirm/cancel modal -->
      <div class="modal-demo-card">
        <h2>Confirmation</h2>
        <p>Cancel/confirm with a primary action.</p>
        <Modal
          title="Save changes?"
          description="You have unsaved edits on this page."
          triggerLabel="Save changes"
          color="primary"
          variant="soft"
          size="md"
          cancelLabel="Discard"
          confirmLabel="Save"
          closeOnConfirm={true}
          @confirm="onSaveConfirmed()"
        >
          <p>Saving will overwrite the previously published version.</p>
        </Modal>
      </div>

      <!-- 3. Destructive confirmation -->
      <div class="modal-demo-card">
        <h2>Destructive action</h2>
        <p>Danger styling for irreversible actions.</p>
        <Modal
          title="Delete account"
          description="This action cannot be undone."
          triggerLabel="Delete account"
          color="danger"
          variant="solid"
          destructive={true}
          cancelLabel="Keep account"
          confirmLabel="Delete account"
          closeOnConfirm={true}
          @confirm="onDeleteConfirmed()"
        >
          <p>
            All of your data, projects, and billing history will be
            permanently removed.
          </p>
        </Modal>
      </div>

      <!-- 4. Form modal. The form owns its own submit button, so the Modal
           footer is turned off: @wrnexus/validation binds to form[data-schema]
           and drives the whole flow (validate on input/blur, block submit
           while invalid, POST to /api/invite, emit wire:success or
           wire:error). Nothing here re-implements a rule that
           app/schemas/invite.ts already states. -->
      <div class="modal-demo-card">
        <h2>Form modal</h2>
        <p>Real Input fields, validated by the shared schema on both sides.</p>
        <Modal
          title="Invite a teammate"
          description="They will get an email with a link to join."
          triggerLabel="Invite teammate"
          color="secondary"
          variant="soft"
          size="md"
          showFooter={false}
        >
          <form
            class="modal-demo-form"
            data-schema="invite"
            method="post"
            action="/api/invite"
            @wire:success="onInviteSent(event)"
            @wire:error="onInviteFailed(event)"
          >
            <Input
              name="email"
              type="email"
              label="Email address"
              placeholder="teammate@company.com"
              autocomplete="email"
              icon="icon-[lucide--mail]"
              required={true}
              helperText="They will get a one-time link to join your workspace."
            />
            <Input
              name="message"
              label="Note (optional)"
              placeholder="Looking forward to working with you"
              maxlength="140"
              icon="icon-[lucide--message-square]"
              cornerHint="Optional"
            />
            <p class="modal-demo-form-error" data-error="_form"></p>
            <button type="submit" class="modal-demo-submit">Send invite</button>
          </form>
        </Modal>
      </div>

      <!-- 5. Large scrollable content, backdrop-click disabled -->
      <div class="modal-demo-card">
        <h2>Scrollable content</h2>
        <p>Larger size, scrollable body, no accidental backdrop dismiss.</p>
        <Modal
          title="Terms of service"
          description="Please review before continuing."
          triggerLabel="Read terms"
          color="primary"
          variant="outline"
          size="lg"
          scrollable={true}
          closeOnBackdrop={false}
          cancelLabel=""
          confirmLabel="I agree"
          closeOnConfirm={true}
          @confirm="onTermsConfirmed()"
        >
          <div class="modal-demo-terms">
            <p>
              This is placeholder terms-of-service copy used to demonstrate a
              tall, scrollable modal body. In a real app this slot would hold
              your actual legal text.
            </p>
            <p>
              1. You agree to use this framework responsibly. 2. Components
              are provided as-is, themed to your app&#39;s palette. 3. Scrollable
              modals keep the header and footer fixed while the body scrolls
              independently, so long content never breaks the layout.
            </p>
            <p>
              4. Clicking the backdrop will not close this particular modal —
              that is controlled by the <code>closeOnBackdrop</code> prop,
              set to <code>false</code> here on purpose so an explicit choice
              is required. 5. Pressing Escape still works, since
              <code>closeOnEscape</code> defaults to <code>true</code>.
            </p>
          </div>
        </Modal>
      </div>

    </div>

    <p class="modal-demo-toast-demos">
      Toast tones:
      <button type="button" @click='toast.success("Everything went through", { title: "Success" })'>success</button>
      <button type="button" @click='toast.error("That did not work", { title: "Error" })'>danger</button>
      <button type="button" @click='onTrialNotice()'>warning + custom icon</button>
      <button type="button" @click='toast.info("Just so you know")'>info</button>
    </p>

    <p
      class="modal-demo-toast-demos"
      @window:demo:restore-note="restoreNote()"
      @window:demo:discard-note="discardNote()"
    >
      Toast actions:
      <button type="button" @click="onDeleteNote()">delete note (undo)</button>
      <button type="button" @click="onConflict()">conflict (two actions)</button>
      <span class="modal-demo-note">Note: <em data-show="noteText">{noteText}</em><em data-show="!noteText">(deleted)</em></span>
    </p>

    <!-- One host per page (a real app puts this in the layout). Every
         toast() call anywhere on the page lands here. -->
    <Toaster position="bottom-right" duration={4500} max={4} />

  }
}
