"use client";

/**
 * The signed-in user's own profile.
 *
 * Only the fields a user may change about themselves — roles, activation and
 * super-admin status stay on the admin path, and the server ignores them here
 * regardless of what this form sends.
 */

import {
  updateMyConsoleProfile,
  uploadMyAvatar,
} from "@/lib/features/users/query";
import type { AdminUserDetailed } from "@/lib/features/users/types";
import {
  Avatar,
  Badge,
  Button,
  Card,
  FileButton,
  Grid,
  Group,
  Stack,
  Text,
  TextInput,
  Title,
} from "@mantine/core";
import {
  IconCamera,
  IconDeviceFloppy,
  IconShieldCheck,
} from "@tabler/icons-react";
import moment from "moment";
import { useState } from "react";
import { useRevalidator } from "react-router";
import { useUser } from "@/providers/UserProvider";
import { toast } from "sonner";

/** Matches the server's cap, so an oversized file fails before the upload. */
const MAX_AVATAR_BYTES = 2 * 1024 * 1024;
const ALLOWED_MIME = ["image/jpeg", "image/png", "image/webp"];

const ProfileClientPage: React.FC<{ profile?: AdminUserDetailed }> = ({
  profile,
}) => {
  const revalidator = useRevalidator();
  /*
   * The header avatar reads from UserProvider, which is filled once at session
   * check. Without updating it here the new photo only appeared after a full
   * reload, so the upload looked like it had not worked.
   */
  const { user, setUser } = useUser();
  const [draft, setDraft] = useState({
    first_name: profile?.first_name ?? "",
    last_name: profile?.last_name ?? "",
    phone: profile?.phone ?? "",
    job_title: profile?.job_title ?? "",
  });
  const [saving, setSaving] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [preview, setPreview] = useState<string | null>(null);

  const name =
    [profile?.first_name, profile?.last_name].filter(Boolean).join(" ") ||
    profile?.email ||
    "";

  const save = async () => {
    setSaving(true);
    const response = await updateMyConsoleProfile(draft);
    setSaving(false);
    if (response?.success) {
      // Keep the header in step with the name just saved.
      if (user) {
        setUser({
          ...user,
          first_name: draft.first_name,
          last_name: draft.last_name,
        });
      }
      toast.success("Profile updated");
      revalidator.revalidate();
    } else {
      toast.error(response?.message ?? "Failed to update profile");
    }
  };

  const upload = async (file: File | null) => {
    if (!file) return;
    if (!ALLOWED_MIME.includes(file.type)) {
      toast.error("Use a JPEG, PNG or WebP image");
      return;
    }
    if (file.size > MAX_AVATAR_BYTES) {
      toast.error("Image must be 2MB or smaller");
      return;
    }
    // Shown immediately; the stored URL replaces it after the reload.
    setPreview(URL.createObjectURL(file));
    setUploading(true);
    const response = await uploadMyAvatar(file);
    setUploading(false);
    if (response?.success) {
      const uploaded = (response.data ?? {}) as { avatar_url?: string | null };
      if (user) {
        setUser({ ...user, avatar_url: uploaded.avatar_url ?? null });
      }
      toast.success("Avatar updated");
      revalidator.revalidate();
    } else {
      setPreview(null);
      toast.error(response?.message ?? "Failed to upload avatar");
    }
  };

  return (
    <Stack gap="lg">
      <Title order={6}>My Profile</Title>

      <Grid gutter="md">
        <Grid.Col span={{ base: 12, md: 4 }}>
          <Card withBorder radius="lg" p="md" h="100%">
            <Stack align="center" gap="sm">
              <Avatar
                src={preview ?? profile?.avatar_url ?? undefined}
                size={104}
                radius={104}
              >
                {(name || "?").slice(0, 2).toUpperCase()}
              </Avatar>
              <FileButton
                onChange={(file) => void upload(file)}
                accept={ALLOWED_MIME.join(",")}
              >
                {(props) => (
                  <Button
                    {...props}
                    variant="light"
                    size="compact-sm"
                    leftSection={<IconCamera size={14} />}
                    loading={uploading}
                  >
                    {profile?.avatar_url ? "Change photo" : "Upload photo"}
                  </Button>
                )}
              </FileButton>
              <Text fz={11} c="dimmed" ta="center">
                JPEG, PNG or WebP · up to 2MB
              </Text>

              <Stack gap={2} align="center" mt="xs">
                <Text fw={600}>{name}</Text>
                <Text fz={12} c="dimmed">
                  {profile?.email}
                </Text>
                {profile?.is_super_admin ? (
                  <Badge
                    variant="light"
                    radius={4}
                    leftSection={<IconShieldCheck size={11} />}
                  >
                    super admin
                  </Badge>
                ) : null}
              </Stack>
            </Stack>
          </Card>
        </Grid.Col>

        <Grid.Col span={{ base: 12, md: 8 }}>
          <Card withBorder radius="lg" p="md">
            <Text fw={600} fz={14} mb="sm">
              Details
            </Text>
            <Grid gutter="md">
              <Grid.Col span={{ base: 12, sm: 6 }}>
                <TextInput
                  label="First name"
                  value={draft.first_name}
                  onChange={(event) => {
                    const first_name = event.currentTarget.value;
                    setDraft((current) => ({ ...current, first_name }));
                  }}
                />
              </Grid.Col>
              <Grid.Col span={{ base: 12, sm: 6 }}>
                <TextInput
                  label="Last name"
                  value={draft.last_name}
                  onChange={(event) => {
                    const last_name = event.currentTarget.value;
                    setDraft((current) => ({ ...current, last_name }));
                  }}
                />
              </Grid.Col>
              <Grid.Col span={{ base: 12, sm: 6 }}>
                <TextInput
                  label="Designation"
                  value={draft.job_title}
                  onChange={(event) => {
                    const job_title = event.currentTarget.value;
                    setDraft((current) => ({ ...current, job_title }));
                  }}
                />
              </Grid.Col>
              <Grid.Col span={{ base: 12, sm: 6 }}>
                <TextInput
                  label="Phone"
                  value={draft.phone}
                  onChange={(event) => {
                    const phone = event.currentTarget.value;
                    setDraft((current) => ({ ...current, phone }));
                  }}
                />
              </Grid.Col>
              {/* Email, username and roles are read-only here: changing them is
                  an administrative act, not a self-service one. */}
              <Grid.Col span={{ base: 12, sm: 6 }}>
                <TextInput
                  label="Email"
                  value={profile?.email ?? ""}
                  disabled
                />
              </Grid.Col>
              <Grid.Col span={{ base: 12, sm: 6 }}>
                <TextInput
                  label="Username"
                  value={profile?.username ?? ""}
                  disabled
                />
              </Grid.Col>
            </Grid>

            <Group justify="space-between" mt="md">
              <Text fz={11} c="dimmed">
                {profile?.last_login_at
                  ? `Last login ${moment(profile.last_login_at).fromNow()}`
                  : "No login recorded yet"}
              </Text>
              <Button
                leftSection={<IconDeviceFloppy size={15} />}
                loading={saving}
                onClick={() => void save()}
              >
                Save changes
              </Button>
            </Group>
          </Card>
        </Grid.Col>
      </Grid>
    </Stack>
  );
};

export default ProfileClientPage;
