import {
  Alert,
  Badge,
  Button,
  Card,
  Group,
  Modal,
  NumberInput,
  Stack,
  Table,
  Tabs,
  Text,
  TextInput,
  Tooltip,
} from "@mantine/core";
import { IconAlertTriangle, IconPlus, IconSeeding } from "@tabler/icons-react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useState } from "react";
import { useTranslation } from "react-i18next";

import { Can } from "@/auth/Can";
import { HR_PERMS } from "@/auth/permissions";
import { apiErrorMessage } from "@/auth/http";
import { PageHeader } from "@/shared/components/PageHeader";
import { BilingualTextInput } from "@/shared/components/BilingualTextInput";
import { localized } from "@/shared/lib/localizedName";
import {
  createWorkSchedule,
  listOvertimeRates,
  listWorkSchedules,
  seedOvertimeRates,
  updateOvertimeRate,
} from "./api";
import { formatMinutes } from "./components/AttendanceStatusBadge";

const DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

export function WorkSchedulesPage() {
  const queryClient = useQueryClient();
  const { i18n } = useTranslation();
  const [adding, setAdding] = useState(false);

  const schedules = useQuery({
    queryKey: ["work-schedules"],
    queryFn: listWorkSchedules,
  });
  const rates = useQuery({ queryKey: ["overtime-rates"], queryFn: listOvertimeRates });

  const seed = useMutation({
    mutationFn: seedOvertimeRates,
    onSuccess: () => queryClient.invalidateQueries({ queryKey: ["overtime-rates"] }),
  });

  const updateRate = useMutation({
    mutationFn: (payload: { id: string; multiplier: string }) =>
      updateOvertimeRate(payload.id, { multiplier: payload.multiplier }),
    onSuccess: () => queryClient.invalidateQueries({ queryKey: ["overtime-rates"] }),
  });

  return (
    <>
      <PageHeader
        title="Attendance settings"
        description="Shift patterns and overtime premiums"
      />

      <Tabs defaultValue="schedules">
        <Tabs.List mb="md">
          <Tabs.Tab value="schedules">Shift patterns</Tabs.Tab>
          <Tabs.Tab value="overtime">Overtime premiums</Tabs.Tab>
        </Tabs.List>

        <Tabs.Panel value="schedules">
          <Group justify="flex-end" mb="sm">
            <Can permission={HR_PERMS.attendance.manageWorkSchedule}>
              <Button leftSection={<IconPlus size={16} />} onClick={() => setAdding(true)}>
                Add pattern
              </Button>
            </Can>
          </Group>

          <Card withBorder radius="md" p={0}>
            <Table.ScrollContainer minWidth={820}>
              <Table striped highlightOnHover verticalSpacing="sm">
                <Table.Thead>
                  <Table.Tr>
                    <Table.Th>Pattern</Table.Th>
                    <Table.Th>Hours</Table.Th>
                    <Table.Th>Break</Table.Th>
                    <Table.Th>Grace</Table.Th>
                    <Table.Th>Days</Table.Th>
                    <Table.Th>Full day at</Table.Th>
                  </Table.Tr>
                </Table.Thead>
                <Table.Tbody>
                  {(schedules.data ?? []).map((schedule) => (
                    <Table.Tr key={schedule.id}>
                      <Table.Td>
                        <Group gap={6}>
                          <Text size="sm" fw={500}>
                            {localized(schedule.name, i18n.language) || schedule.code}
                          </Text>
                          {schedule.isDefault && (
                            <Badge size="xs" variant="light">
                              default
                            </Badge>
                          )}
                          {schedule.crossesMidnight && (
                            <Badge size="xs" variant="light" color="grape">
                              night
                            </Badge>
                          )}
                          {!schedule.isActive && (
                            <Badge size="xs" variant="light" color="gray">
                              inactive
                            </Badge>
                          )}
                        </Group>
                        <Text size="xs" c="dimmed">
                          {schedule.code}
                        </Text>
                      </Table.Td>
                      <Table.Td>
                        <Text size="sm">
                          {schedule.startTime.slice(0, 5)} —{" "}
                          {schedule.endTime.slice(0, 5)}
                        </Text>
                      </Table.Td>
                      <Table.Td>
                        <Text size="sm">{schedule.breakMinutes}m</Text>
                      </Table.Td>
                      <Table.Td>
                        <Tooltip label="Arrive within this and nothing is recorded">
                          <Text size="sm">{schedule.gracePeriodMinutes}m</Text>
                        </Tooltip>
                      </Table.Td>
                      <Table.Td>
                        {schedule.workingDays?.length ? (
                          <Group gap={2}>
                            {schedule.workingDays.map((day) => (
                              <Badge key={day} size="xs" variant="default">
                                {DAY_NAMES[day]}
                              </Badge>
                            ))}
                          </Group>
                        ) : (
                          <Text size="xs" c="dimmed">
                            company week
                          </Text>
                        )}
                      </Table.Td>
                      <Table.Td>
                        <Text size="sm">{formatMinutes(schedule.minMinutesFullDay)}</Text>
                        <Text size="xs" c="dimmed">
                          half at {formatMinutes(schedule.minMinutesHalfDay)}
                        </Text>
                      </Table.Td>
                    </Table.Tr>
                  ))}
                  {!schedules.isLoading && (schedules.data ?? []).length === 0 && (
                    <Table.Tr>
                      <Table.Td colSpan={6}>
                        <Text size="sm" c="dimmed" ta="center" py="lg">
                          No shift patterns yet. Without one, punches are recorded
                          but lateness cannot be judged.
                        </Text>
                      </Table.Td>
                    </Table.Tr>
                  )}
                </Table.Tbody>
              </Table>
            </Table.ScrollContainer>
          </Card>
        </Tabs.Panel>

        <Tabs.Panel value="overtime">
          <Group justify="flex-end" mb="sm">
            <Can permission={HR_PERMS.attendance.approveOvertime}>
              <Button
                variant="default"
                leftSection={<IconSeeding size={16} />}
                loading={seed.isPending}
                onClick={() => seed.mutate()}
              >
                Add statutory premiums
              </Button>
            </Can>
          </Group>

          <Alert color="blue" variant="light" mb="md">
            Proclamation 1156/2019 Art. 68 sets these as a <strong>floor</strong>.
            You may pay more; the API refuses less.
          </Alert>

          {updateRate.isError && (
            <Alert color="red" mb="md" icon={<IconAlertTriangle size={18} />}>
              {apiErrorMessage(updateRate.error)}
            </Alert>
          )}

          <Card withBorder radius="md" p={0}>
            <Table striped verticalSpacing="sm">
              <Table.Thead>
                <Table.Tr>
                  <Table.Th>When</Table.Th>
                  <Table.Th>Multiplier</Table.Th>
                  <Table.Th>Cap per day</Table.Th>
                  <Table.Th>Basis</Table.Th>
                </Table.Tr>
              </Table.Thead>
              <Table.Tbody>
                {(rates.data ?? []).map((rate) => (
                  <Table.Tr key={rate.id}>
                    <Table.Td>
                      <Text size="sm" tt="capitalize">
                        {rate.category.replace("_", " ").toLowerCase()}
                      </Text>
                    </Table.Td>
                    <Table.Td>
                      <Can permission={HR_PERMS.attendance.approveOvertime}>
                        <NumberInput
                          size="xs"
                          w={110}
                          min={1}
                          max={10}
                          step={0.25}
                          decimalScale={2}
                          suffix="×"
                          defaultValue={Number(rate.multiplier)}
                          onBlur={(event) => {
                            const value = event.currentTarget.value.replace("×", "");
                            if (Number(value) !== Number(rate.multiplier)) {
                              updateRate.mutate({
                                id: rate.id,
                                multiplier: Number(value).toFixed(2),
                              });
                            }
                          }}
                        />
                      </Can>
                    </Table.Td>
                    <Table.Td>
                      <Text size="sm">
                        {rate.maxHoursPerDay ? `${Number(rate.maxHoursPerDay)}h` : "—"}
                      </Text>
                    </Table.Td>
                    <Table.Td>
                      <Text size="xs" c="dimmed">
                        {rate.statuteReference ?? "—"}
                      </Text>
                    </Table.Td>
                  </Table.Tr>
                ))}
                {(rates.data ?? []).length === 0 && (
                  <Table.Tr>
                    <Table.Td colSpan={4}>
                      <Text size="sm" c="dimmed" ta="center" py="lg">
                        No premiums configured — overtime cannot be claimed until
                        there are. "Add statutory premiums" creates them.
                      </Text>
                    </Table.Td>
                  </Table.Tr>
                )}
              </Table.Tbody>
            </Table>
          </Card>
        </Tabs.Panel>
      </Tabs>

      <AddScheduleModal opened={adding} onClose={() => setAdding(false)} />
    </>
  );
}

function AddScheduleModal({
  opened,
  onClose,
}: {
  opened: boolean;
  onClose: () => void;
}) {
  const queryClient = useQueryClient();
  const [code, setCode] = useState("");
  const [name, setName] = useState({ am: "", en: "" });
  const [startTime, setStartTime] = useState("08:30");
  const [endTime, setEndTime] = useState("17:30");
  const [breakMinutes, setBreakMinutes] = useState(60);
  const [grace, setGrace] = useState(10);

  const create = useMutation({
    mutationFn: () =>
      createWorkSchedule({
        code,
        name,
        startTime,
        endTime,
        breakMinutes,
        gracePeriodMinutes: grace,
        // A shift finishing before it starts must be a night shift; saying so
        // here avoids a refusal the user cannot act on.
        crossesMidnight: endTime <= startTime,
      }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["work-schedules"] });
      setCode("");
      setName({ am: "", en: "" });
      onClose();
    },
  });

  return (
    <Modal opened={opened} onClose={onClose} title="Add a shift pattern" centered>
      <Stack>
        {create.isError && (
          <Alert color="red" icon={<IconAlertTriangle size={18} />}>
            {apiErrorMessage(create.error)}
          </Alert>
        )}
        <TextInput
          label="Code"
          required
          placeholder="STANDARD"
          value={code}
          onChange={(event) => setCode(event.currentTarget.value.toUpperCase())}
        />
        <BilingualTextInput label="Name" required value={name} onChange={setName} />
        <Group grow>
          <TextInput
            label="Starts"
            required
            type="time"
            value={startTime}
            onChange={(event) => setStartTime(event.currentTarget.value)}
          />
          <TextInput
            label="Ends"
            required
            type="time"
            value={endTime}
            onChange={(event) => setEndTime(event.currentTarget.value)}
          />
        </Group>
        {endTime <= startTime && (
          <Alert color="grape" variant="light">
            This ends before it starts, so it will be treated as a night shift
            running into the next day.
          </Alert>
        )}
        <Group grow>
          <NumberInput
            label="Break"
            suffix=" min"
            min={0}
            max={480}
            value={breakMinutes}
            onChange={(value) => setBreakMinutes(Number(value) || 0)}
          />
          <NumberInput
            label="Grace period"
            suffix=" min"
            min={0}
            max={240}
            description="Later than this counts as late"
            value={grace}
            onChange={(value) => setGrace(Number(value) || 0)}
          />
        </Group>
        <Group justify="flex-end">
          <Button variant="default" onClick={onClose}>
            Cancel
          </Button>
          <Button
            loading={create.isPending}
            disabled={!code || !name.en}
            onClick={() => create.mutate()}
          >
            Add
          </Button>
        </Group>
      </Stack>
    </Modal>
  );
}
