---
import { z } from 'astro/zod'
import { Icon } from 'astro-icon/components'
import { actions } from 'astro:actions'

import Button from '../components/Button.astro'
import CopyButton from '../components/CopyButton.astro'
import PushNotificationBanner from '../components/PushNotificationBanner.astro'
import TimeFormatted from '../components/TimeFormatted.astro'
import Tooltip from '../components/Tooltip.astro'
import { getNotificationTypeInfo } from '../constants/notificationTypes'
import BaseLayout from '../layouts/BaseLayout.astro'
import { cn } from '../lib/cn'
import { getOrCreateNotificationPreferences } from '../lib/notificationPreferences'
import { makeNotificationActions, makeNotificationContent, makeNotificationTitle } from '../lib/notifications'
import { zodParseQueryParamsStoringErrors } from '../lib/parseUrlFilters'
import { prisma } from '../lib/prisma'
import { makeLoginUrl } from '../lib/redirectUrls'

const user = Astro.locals.user
if (!user) return Astro.redirect(makeLoginUrl(Astro.url))

const PAGE_SIZE = 20

const { data: params } = zodParseQueryParamsStoringErrors(
  {
    page: z.coerce.number().int().min(1).default(1),
  },
  Astro
)
const skip = (params.page - 1) * PAGE_SIZE

const [dbNotifications, notificationPreferences, totalNotifications, pushSubscriptions] =
  await Astro.locals.banners.tryMany([
    [
      'Error while fetching notifications',
      () =>
        prisma.notification.findMany({
          where: {
            userId: user.id,
          },
          orderBy: {
            createdAt: 'desc',
          },
          skip,
          take: PAGE_SIZE,
          select: {
            id: true,
            type: true,
            createdAt: true,
            read: true,
            aboutAccountStatusChange: true,
            aboutCommentStatusChange: true,
            aboutServiceVerificationStatusChange: true,
            aboutSuggestionStatusChange: true,
            aboutComment: {
              select: {
                id: true,
                author: {
                  select: {
                    id: true,
                  },
                },
                status: true,
                content: true,
                communityNote: true,
                service: {
                  select: {
                    slug: true,
                    name: true,
                  },
                },
                parent: {
                  select: {
                    author: {
                      select: {
                        id: true,
                      },
                    },
                  },
                },
              },
            },
            aboutServiceSuggestionId: true,
            aboutServiceSuggestion: {
              select: {
                status: true,
                type: true,
                service: {
                  select: {
                    name: true,
                  },
                },
              },
            },
            aboutServiceSuggestionMessage: {
              select: {
                id: true,
                content: true,
                suggestion: {
                  select: {
                    id: true,
                    service: {
                      select: {
                        name: true,
                      },
                    },
                  },
                },
              },
            },
            aboutEvent: {
              select: {
                title: true,
                type: true,
                service: {
                  select: {
                    slug: true,
                    name: true,
                  },
                },
              },
            },
            aboutService: {
              select: {
                slug: true,
                name: true,
                verificationStatus: true,
              },
            },
            aboutKarmaTransaction: {
              select: {
                points: true,
                action: true,
                description: true,
              },
            },
          },
        }),
      [],
    ],
    [
      'Error while fetching notification preferences',
      () =>
        getOrCreateNotificationPreferences(user.id, {
          id: true,
          enableOnMyCommentStatusChange: true,
          enableAutowatchMyComments: true,
          enableNotifyPendingRepliesOnWatch: true,
          karmaNotificationThreshold: true,
        }),
      null,
    ],
    [
      'Error while fetching total notifications',
      () => prisma.notification.count({ where: { userId: user.id } }),
      0,
    ],
    [
      'Error while fetching push subscriptions',
      () =>
        prisma.pushSubscription.findMany({
          where: { userId: user.id },
          select: {
            endpoint: true,
          },
        }),
      [],
    ],
  ])

if (!notificationPreferences) console.error('No notification preferences found')

const totalPages = Math.ceil(totalNotifications / PAGE_SIZE)

const notificationPreferenceFields = [
  {
    id: 'enableOnMyCommentStatusChange',
    label: 'Notify me when my comment status changes.',
    icon: 'ri:chat-check-line',
  },
  {
    id: 'enableAutowatchMyComments',
    label: 'Autowatch my comments to receive notifications when they get a new reply.',
    icon: 'ri:eye-line',
  },
  {
    id: 'enableNotifyPendingRepliesOnWatch',
    label: 'Notify me also about unmoderated replies for watched comments.',
    icon: 'ri:chat-delete-line',
  },
] as const satisfies {
  id: Omit<keyof NonNullable<typeof notificationPreferences>, 'id'>
  label: string
  icon: string
}[]

const notifications = dbNotifications.map((notification) => ({
  ...notification,
  typeInfo: getNotificationTypeInfo(notification.type),
  title: makeNotificationTitle(notification, user),
  content: makeNotificationContent(notification),
  actions: makeNotificationActions(notification, Astro.url.origin),
}))
---

<BaseLayout
  pageTitle="Notifications"
  description="View your notifications and manage your notification preferences."
  widthClassName="max-w-screen-lg"
  ogImage={{
    template: 'generic',
    title: 'Notifications',
    description: 'View and manage your notifications',
    icon: 'ri:notification-line',
  }}
>
  <section class="mx-auto w-full">
    {
      notifications.length >= 5 && (
        <PushNotificationBanner
          class="mb-4"
          dismissable
          pushSubscriptions={pushSubscriptions}
          hideIfEnabled
        />
      )
    }

    <div class="mb-4 flex items-center justify-between">
      <h1 class="font-title flex items-center text-2xl leading-tight font-bold tracking-wider">
        <Icon name="ri:notification-line" class="mr-2 size-6 text-zinc-400" />
        Notifications
      </h1>

      <form method="POST" action={actions.notification.updateReadStatus}>
        <input type="hidden" name="notificationId" value="all" />
        <input type="hidden" name="read" value="true" />
        <Button
          type="submit"
          label="Mark all as read"
          icon="ri:check-double-line"
          disabled={notifications.length === 0}
          color="white"
        />
      </form>
    </div>

    <div
      class="mb-4 flex items-center gap-2 rounded-lg border border-blue-500/20 bg-blue-500/10 p-3 text-blue-200"
      data-new-notification-banner
      style={{ display: 'none' }}
    >
      <span>You received a new notification</span>
      <Button
        type="button"
        label="Reload"
        icon="ri:refresh-line"
        color="white"
        class="no-js:hidden ml-auto"
        onclick="window.location.reload()"
      />
    </div>

    {
      notifications.length === 0 ? (
        <div class="flex flex-col items-center justify-center rounded-lg border border-zinc-800 bg-zinc-900 p-10 text-center shadow-sm">
          <Icon name="material-symbols:notifications-outline" class="size-16 text-zinc-600" />
          <h3 class="font-title mt-2 text-zinc-400">No notifications</h3>
        </div>
      ) : (
        <div class="space-y-2">
          {notifications.map((notification) => (
            <div
              class={cn('rounded-lg border border-l-4 border-zinc-800 bg-zinc-900 p-3 shadow-sm', {
                'border-l-blue-600': !notification.read,
              })}
            >
              <div class="flex items-start justify-between">
                <div class="flex items-start gap-3">
                  <div class="mt-0.5 rounded-md bg-zinc-800 p-2">
                    <Icon name={notification.typeInfo.icon} class="size-5 text-zinc-300" />
                  </div>

                  <div>
                    <div class="font-medium text-zinc-200">{notification.title}</div>
                    <p class="text-sm wrap-anywhere text-zinc-400">{notification.content}</p>
                    <div class="mt-1 text-xs text-zinc-500">
                      <TimeFormatted date={notification.createdAt} prefix={false} caseType="sentence" />
                    </div>
                  </div>
                </div>

                <div class="flex items-center gap-2">
                  <form method="POST" action={actions.notification.updateReadStatus}>
                    <input type="hidden" name="notificationId" value={notification.id} />
                    <input type="hidden" name="read" value={notification.read ? 'false' : 'true'} />
                    <Tooltip
                      as="button"
                      text={notification.read ? 'Mark as unread' : 'Mark as read'}
                      position="left"
                      type="submit"
                      class="flex size-8 items-center justify-center rounded-full border border-zinc-700 bg-zinc-800 text-zinc-400 transition-colors duration-200 hover:bg-zinc-700 hover:text-zinc-200"
                    >
                      <Icon name={notification.read ? 'ri:close-line' : 'ri:check-line'} class="size-4" />
                    </Tooltip>
                  </form>
                  {notification.actions.map((action) => (
                    <Tooltip
                      as="a"
                      href={action.url}
                      class="flex size-8 items-center justify-center rounded-full border border-zinc-700 bg-zinc-800 text-zinc-400 transition-colors duration-200 hover:bg-zinc-700 hover:text-zinc-200"
                      text={action.title}
                      position="left"
                    >
                      <Icon name={action.iconName ?? 'ri:arrow-right-line'} class="size-4" />
                      <span class="sr-only">{action.title}</span>
                    </Tooltip>
                  ))}
                </div>
              </div>
            </div>
          ))}

          {totalPages > 1 && (
            <div class="mt-8 flex justify-center gap-4">
              <form method="GET" action="/notifications" class="inline">
                <input type="hidden" name="page" value={params.page - 1} />
                <button
                  type="submit"
                  class="rounded-md border border-zinc-700 bg-zinc-800 px-4 py-2 text-sm text-zinc-200 transition-colors duration-200 hover:bg-zinc-700"
                  disabled={params.page <= 1}
                >
                  Previous
                </button>
              </form>
              <span class="inline-flex items-center px-2 text-sm text-zinc-400">
                Page {params.page} of {totalPages}
              </span>
              <form method="GET" action="/notifications" class="inline">
                <input type="hidden" name="page" value={params.page + 1} />
                <button
                  type="submit"
                  class="rounded-md border border-zinc-700 bg-zinc-800 px-4 py-2 text-sm text-zinc-200 transition-colors duration-200 hover:bg-zinc-700"
                  disabled={params.page >= totalPages}
                >
                  Next
                </button>
              </form>
            </div>
          )}
        </div>
      )
    }

    <h2 class="font-title mt-8 mb-3 flex items-center border-b border-zinc-800 text-lg font-bold">
      <Icon name="ri:settings-3-line" class="mr-2 size-5 text-zinc-400" />
      Notification Settings
    </h2>

    <PushNotificationBanner class="mb-3" pushSubscriptions={pushSubscriptions} />

    <form
      method="POST"
      action={actions.notification.preferences.update}
      class="rounded-lg border border-zinc-800 bg-zinc-900 p-4 shadow-sm"
    >
      {
        notificationPreferenceFields.map((field) => (
          <label class="flex items-center justify-between rounded-md p-2 transition-colors duration-200 hover:bg-zinc-800">
            <span class="flex items-center text-zinc-300">
              <Icon name={field.icon} class="mr-2 size-5 text-zinc-400" />
              {field.label}
            </span>
            <input
              type="checkbox"
              name={field.id}
              checked={notificationPreferences?.[field.id]}
              class="size-4 rounded border-zinc-700 bg-zinc-800 text-blue-600 focus:ring-blue-600"
            />
          </label>
        ))
      }

      <div
        class="mt-4 flex items-center justify-between rounded-md p-2 transition-colors duration-200 hover:bg-zinc-800"
      >
        <span class="flex items-center text-zinc-300">
          <Icon name="ri:award-line" class="mr-2 size-5 text-zinc-400" />
          Notify me when my karma changes by at least
        </span>
        <div class="flex items-center gap-2">
          <input
            type="number"
            name="karmaNotificationThreshold"
            value={notificationPreferences?.karmaNotificationThreshold}
            min="1"
            class="w-20 rounded border border-zinc-700 bg-zinc-800 px-2 py-1 text-zinc-200 focus:border-blue-600 focus:ring-1 focus:ring-blue-600 focus:outline-none"
          />
          <span class="text-zinc-400">points</span>
        </div>
      </div>

      <div class="mt-4 flex justify-end">
        <Button type="submit" label="Save" icon="ri:save-line" color="success" />
      </div>
    </form>

    <div
      class="relative isolate mt-3 overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900 p-6 shadow-sm"
    >
      <div aria-hidden="true" class="pointer-events-none absolute inset-0 -z-10 overflow-hidden">
        <div
          class="absolute top-0 -left-16 h-full w-1/3 bg-gradient-to-r from-zinc-500/20 to-transparent opacity-50 blur-xl"
        >
        </div>
        <div
          class="absolute top-0 -right-16 h-full w-1/3 bg-gradient-to-l from-zinc-500/20 to-transparent opacity-50 blur-xl"
        >
        </div>
      </div>

      <div class="mb-4 flex items-center gap-3">
        <div class="rounded-md bg-zinc-800 p-2">
          <Icon name="ri:rss-line" class="size-6 text-zinc-300" />
        </div>
        <h3 class="font-title text-xl font-bold text-zinc-200">RSS feeds available</h3>
      </div>

      <div class="space-y-4">
        <div>
          <p class="mb-1 text-sm text-zinc-400">
            Subscribe to receive your notifications in your favorite RSS reader.
          </p>
          <div class="flex items-center gap-2">
            <input
              type="text"
              readonly
              value={`${Astro.url.origin}/feeds/user/${user.feedId}/notifications.xml`}
              class="flex-1 rounded border border-zinc-700 bg-zinc-800 px-3 py-2 text-sm text-zinc-200 select-all"
            />
            <CopyButton
              copyText={`${Astro.url.origin}/feeds/user/${user.feedId}/notifications.xml`}
              color="white"
            />
          </div>
        </div>

        <a
          href="/feeds"
          class="flex items-center justify-between rounded-lg border border-zinc-700/50 bg-zinc-800/30 p-3"
        >
          <div>
            <h4 class="text-sm font-semibold text-zinc-300">Public RSS feeds</h4>
            <p class="text-xs text-zinc-500">
              Don't require an account to subscribe. Includes service comments and events.
            </p>
          </div>
          <Button
            as="span"
            label="Browse all"
            icon="ri:arrow-right-line"
            variant="faded"
            color="white"
            class="pointer-events-none"
          />
        </a>
      </div>
    </div>
  </section>
</BaseLayout>

<script>
  document.addEventListener('sse:new-notification', () => {
    document.querySelectorAll<HTMLElement>('[data-new-notification-banner]').forEach((banner) => {
      banner.style.display = ''
    })
  })
</script>
