import { useEffect, useState, type ReactElement } from 'react';
import { format } from 'date-fns';
import { type Control } from 'react-hook-form';
import { Link } from 'react-router-dom';
import { toast } from 'sonner';
import { useQuery } from 'urql';
import { Select, Text } from '@mantine/core';
import { ROUTES } from '@/router/routes.js';
import {
  AttendeesByBusinessTripDocument,
  BusinessTripReportCoreExpenseRowFieldsFragmentDoc,
  Currency,
  type UpdateBusinessTripTravelAndSubsistenceExpenseInput,
} from '../../../../gql/graphql.js';
import { getFragmentData, type FragmentType } from '../../../../gql/index.js';
import { TIMELESS_DATE_REGEX } from '../../../../helpers/consts.js';
import { FormControl, FormField, FormItem, FormLabel, FormMessage } from '../../../ui/form.js';
import { CurrencyInput, DatePickerInput } from '../../index.js';

// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- used by codegen
/* GraphQL */ `
  fragment BusinessTripReportCoreExpenseRowFields on BusinessTripExpense {
    id
    date
    valueDate
    amount {
      formatted
      raw
      currency
    }
    employee {
      id
      name
    }
    payedByEmployee
    charges {
      id
    }
  }
`;

export type UpdateBusinessTripExpenseInput = Omit<
  UpdateBusinessTripTravelAndSubsistenceExpenseInput,
  'expenseType'
>;

interface Props {
  data: FragmentType<typeof BusinessTripReportCoreExpenseRowFieldsFragmentDoc>;
  isEditMode: boolean;
  control: Control<UpdateBusinessTripExpenseInput, unknown>;
  businessTripId: string;
}

export const CoreExpenseRow = ({
  data,
  isEditMode = false,
  control,
  businessTripId,
}: Props): ReactElement => {
  const businessTripExpense = getFragmentData(
    BusinessTripReportCoreExpenseRowFieldsFragmentDoc,
    data,
  );

  const [attendees, setAttendees] = useState<Array<{ value: string; label: string }>>([]);

  const [{ data: attendeesData, fetching: fetchingAttendees, error }] = useQuery({
    query: AttendeesByBusinessTripDocument,
    variables: { businessTripId },
  });

  // On every new data fetch, reorder results by name
  useEffect(() => {
    if (attendeesData?.businessTrip?.attendees.length) {
      setAttendees(
        attendeesData.businessTrip.attendees
          .map(attendee => ({
            value: attendee.id,
            label: attendee.name,
          }))
          .sort((a, b) => (a.label > b.label ? 1 : -1)),
      );
    }
  }, [attendeesData, setAttendees]);

  useEffect(() => {
    if (error) {
      toast.error('Error', {
        description: 'Oops, we have an error fetching attendees',
      });
    }
  }, [error]);

  const linkedChargeIds = Array.from(new Set(businessTripExpense.charges?.map(c => c.id)));

  return (
    <>
      <td>
        <div className="flex flex-col gap-2 justify-center">
          {isEditMode && businessTripExpense.payedByEmployee ? (
            <>
              <FormField
                name="date"
                control={control}
                defaultValue={businessTripExpense.date}
                rules={{
                  pattern: {
                    value: TIMELESS_DATE_REGEX,
                    message: 'Date must be in format yyyy-mm-dd',
                  },
                }}
                render={({ field, fieldState }): ReactElement => (
                  <FormItem className="h-min">
                    <FormLabel htmlFor={`business-trip-expense-date-${businessTripExpense.id}`}>
                      Date
                    </FormLabel>
                    <FormControl>
                      <DatePickerInput
                        id={`business-trip-expense-date-${businessTripExpense.id}`}
                        form={`form ${businessTripExpense.id}`}
                        data-autofocus
                        value={field.value ?? undefined}
                        onChange={date => {
                          if (date !== field.value) field.onChange(date);
                        }}
                        aria-invalid={!!fieldState.error}
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
              <FormField
                name="valueDate"
                control={control}
                defaultValue={businessTripExpense.valueDate}
                rules={{
                  pattern: {
                    value: TIMELESS_DATE_REGEX,
                    message: 'Date must be in format yyyy-mm-dd',
                  },
                }}
                render={({ field, fieldState }): ReactElement => (
                  <FormItem className="h-min">
                    <FormLabel>Value Date</FormLabel>
                    <FormControl>
                      <DatePickerInput
                        form={`form ${businessTripExpense.id}`}
                        value={field.value ?? undefined}
                        onChange={date => {
                          if (date !== field.value) field.onChange(date);
                        }}
                        aria-invalid={!!fieldState.error}
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
            </>
          ) : (
            <>
              {businessTripExpense.date && format(new Date(businessTripExpense.date), 'dd/MM/yy')}
              <Text fz="sm" c="dimmed">
                {businessTripExpense.valueDate &&
                  format(new Date(businessTripExpense.valueDate), 'dd/MM/yy')}
              </Text>
            </>
          )}
        </div>
      </td>
      <td>
        {isEditMode && businessTripExpense.payedByEmployee ? (
          <FormField
            name="amount"
            control={control}
            defaultValue={businessTripExpense.amount?.raw ?? undefined}
            render={({ field: amountField, fieldState: amountFieldState }): ReactElement => (
              <FormField
                name="currency"
                control={control}
                defaultValue={businessTripExpense.amount?.currency ?? Currency.Ils}
                render={({
                  field: currencyCodeField,
                  fieldState: currencyCodeFieldState,
                }): ReactElement => (
                  <CurrencyInput
                    form={`form ${businessTripExpense.id}`}
                    {...amountField}
                    value={amountField.value ?? undefined}
                    error={amountFieldState.error?.message || currencyCodeFieldState.error?.message}
                    label="Amount"
                    currencyCodeProps={{
                      ...currencyCodeField,
                      label: 'Currency',
                      form: `form ${businessTripExpense.id}`,
                    }}
                  />
                )}
              />
            )}
          />
        ) : (
          <div>{businessTripExpense.amount?.formatted}</div>
        )}
      </td>
      <td>
        <div className="flex flex-col gap-2 justify-center">
          {isEditMode && businessTripExpense.payedByEmployee ? (
            <FormField
              name="employeeBusinessId"
              control={control}
              defaultValue={businessTripExpense.employee?.id}
              render={({ field, fieldState }): ReactElement => (
                <Select
                  form={`form ${businessTripExpense.id}`}
                  {...field}
                  data={attendees}
                  value={field.value}
                  disabled={fetchingAttendees}
                  label="Attendee"
                  placeholder="Scroll to see all options"
                  maxDropdownHeight={160}
                  searchable
                  error={fieldState.error?.message}
                  withinPortal
                />
              )}
            />
          ) : (
            <div className="flex flex-row gap-2 items-center">
              {businessTripExpense.payedByEmployee && (
                <Text c={businessTripExpense.employee?.name ? undefined : 'red'}>
                  {businessTripExpense.employee?.name ?? 'Missing'}
                </Text>
              )}
            </div>
          )}
        </div>
      </td>
      <td>
        <div className="flex flex-col gap-2">
          {linkedChargeIds.map(id => (
            <Link
              key={id}
              to={ROUTES.CHARGES.DETAIL(id)}
              target="_blank"
              rel="noreferrer"
              onClick={event => event.stopPropagation()}
              className="inline-flex items-center font-semibold"
            >
              To Charge
            </Link>
          ))}
        </div>
      </td>
    </>
  );
};

export const CoreExpenseHeader = (): ReactElement => {
  return (
    <>
      <th>Date</th>
      <th>Amount</th>
      <th>Payed By Attendee</th>
      <th>Charges</th>
    </>
  );
};
