import { Box, Paper, Typography } from '@mui/material';
import React, { useState } from 'react';
import ToolContent from '@components/ToolContent';
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
import SelectWithDesc from '@components/options/SelectWithDesc';
import {
  calculateTimeBetweenDates,
  formatTimeWithLargestUnit,
  getTimeWithTimezone,
  unitHierarchy
} from './service';
import * as Yup from 'yup';
import { CardExampleType } from '@components/examples/ToolExamples';

type TimeUnit =
  | 'milliseconds'
  | 'seconds'
  | 'minutes'
  | 'hours'
  | 'days'
  | 'months'
  | 'years';

type InitialValuesType = {
  startDate: string;
  startTime: string;
  endDate: string;
  endTime: string;
  startTimezone: string;
  endTimezone: string;
};

const initialValues: InitialValuesType = {
  startDate: new Date().toISOString().split('T')[0],
  startTime: '00:00',
  endDate: new Date().toISOString().split('T')[0],
  endTime: '12:00',
  startTimezone: 'local',
  endTimezone: 'local'
};

const validationSchema = Yup.object({
  startDate: Yup.string().required('Start date is required'),
  startTime: Yup.string().required('Start time is required'),
  endDate: Yup.string().required('End date is required'),
  endTime: Yup.string().required('End time is required'),
  startTimezone: Yup.string(),
  endTimezone: Yup.string()
});

const timezoneOptions = [
  { value: 'local', label: 'Local Time' },
  ...Intl.supportedValuesOf('timeZone')
    .map((tz) => {
      const formatter = new Intl.DateTimeFormat('en', {
        timeZone: tz,
        timeZoneName: 'shortOffset'
      });

      const offset =
        formatter
          .formatToParts(new Date())
          .find((part) => part.type === 'timeZoneName')?.value || '';

      return {
        value: offset.replace('UTC', 'GMT'),
        label: `${offset.replace('UTC', 'GMT')} (${tz})`
      };
    })
    .sort((a, b) =>
      a.value.localeCompare(b.value, undefined, { numeric: true })
    )
];

const exampleCards: CardExampleType<InitialValuesType>[] = [
  {
    title: 'One Year Difference',
    description: 'Calculate the time between dates that are one year apart',
    sampleOptions: {
      startDate: '2023-01-01',
      startTime: '12:00',
      endDate: '2024-01-01',
      endTime: '12:00',
      startTimezone: 'local',
      endTimezone: 'local'
    },
    sampleResult: '1 year'
  },
  {
    title: 'Different Timezones',
    description: 'Calculate the time difference between New York and London',
    sampleOptions: {
      startDate: '2023-01-01',
      startTime: '12:00',
      endDate: '2023-01-01',
      endTime: '12:00',
      startTimezone: 'GMT-5',
      endTimezone: 'GMT'
    },
    sampleResult: '5 hours'
  },
  {
    title: 'Detailed Time Breakdown',
    description: 'Show a detailed breakdown of a time difference',
    sampleOptions: {
      startDate: '2023-01-01',
      startTime: '09:30',
      endDate: '2023-01-03',
      endTime: '14:45',
      startTimezone: 'local',
      endTimezone: 'local'
    },
    sampleResult: '2 days, 5 hours, 15 minutes'
  }
];

export default function TimeBetweenDates() {
  const [result, setResult] = useState<string>('');

  return (
    <ToolContent
      title="Time Between Dates"
      inputComponent={null}
      resultComponent={
        result ? (
          <Paper
            elevation={3}
            sx={{
              p: 3,
              borderLeft: '5px solid',
              borderColor: 'primary.main',
              bgcolor: 'background.paper',
              maxWidth: '100%',
              mx: 'auto'
            }}
          >
            <Typography
              variant="h4"
              align="center"
              sx={{ fontWeight: 'bold', color: 'primary.main' }}
            >
              {result}
            </Typography>
          </Paper>
        ) : null
      }
      initialValues={initialValues}
      validationSchema={validationSchema}
      exampleCards={exampleCards}
      toolInfo={{
        title: 'Time Between Dates Calculator',
        description:
          'Calculate the exact time difference between two dates and times, with support for different timezones. This tool provides a detailed breakdown of the time difference in various units (years, months, days, hours, minutes, and seconds).'
      }}
      getGroups={({ values, updateField }) => [
        {
          title: 'Start Date & Time',
          component: (
            <Box>
              <TextFieldWithDesc
                description="Start Date"
                value={values.startDate}
                onOwnChange={(val) => updateField('startDate', val)}
                type="date"
              />
              <TextFieldWithDesc
                description="Start Time"
                value={values.startTime}
                onOwnChange={(val) => updateField('startTime', val)}
                type="time"
              />
              <SelectWithDesc
                description="Start Timezone"
                selected={values.startTimezone}
                onChange={(val: string) => updateField('startTimezone', val)}
                options={timezoneOptions}
              />
            </Box>
          )
        },
        {
          title: 'End Date & Time',
          component: (
            <Box>
              <TextFieldWithDesc
                description="End Date"
                value={values.endDate}
                onOwnChange={(val) => updateField('endDate', val)}
                type="date"
              />
              <TextFieldWithDesc
                description="End Time"
                value={values.endTime}
                onOwnChange={(val) => updateField('endTime', val)}
                type="time"
              />
              <SelectWithDesc
                description="End Timezone"
                selected={values.endTimezone}
                onChange={(val: string) => updateField('endTimezone', val)}
                options={timezoneOptions}
              />
            </Box>
          )
        }
      ]}
      compute={(values) => {
        try {
          const startDateTime = getTimeWithTimezone(
            values.startDate,
            values.startTime,
            values.startTimezone
          );

          const endDateTime = getTimeWithTimezone(
            values.endDate,
            values.endTime,
            values.endTimezone
          );

          // Calculate time difference
          const difference = calculateTimeBetweenDates(
            startDateTime,
            endDateTime
          );

          // Auto-determine the best unit to display based on the time difference
          const bestUnit: TimeUnit =
            unitHierarchy.find((unit) => difference[unit] > 0) ||
            'milliseconds';

          const formattedDifference = formatTimeWithLargestUnit(
            difference,
            bestUnit
          );

          setResult(formattedDifference);
        } catch (error) {
          setResult(
            `Error: ${
              error instanceof Error
                ? error.message
                : 'Failed to calculate time difference'
            }`
          );
        }
      }}
    />
  );
}
