import { GetServerSideProps } from 'next'
import React, { useEffect, useState } from 'react'
import Footer from '../../../components/footer'
import Header from '../../../components/header'
import Input from '../../../components/input'
import { AdditionalCosts, BillDocument } from '../../../db/bill'
import { BookingDocument } from '../../../db/booking'
import {
  BILL_STATUS,
  MILAGE_RATES,
  getMilageRateValue,
} from '../../../db/enums'
import { getBookingByUUID } from '../../../db/index'
import { dateFormatFrontend } from '../../../helpers/date'

export const getServerSideProps: GetServerSideProps = async (context) => {
  const {
    res,
    params: { uuid: uuids },
  } = context
  const uuid = Array.isArray(uuids) ? uuids[0] : uuids
  const booking = await getBookingByUUID(uuid)
  await booking.populate('booker').populate('bill').execPopulate()

  if (!booking) {
    res.statusCode = 404
    res.end()
    return { props: {} }
  }
  // TODO: hack, not sure why _id is not serilizable
  const bookingJSON = JSON.parse(JSON.stringify(booking.toJSON()))
  return {
    props: { booking: bookingJSON },
  }
}

function getRateLabel(rate: MILAGE_RATES) {
  switch (rate) {
    case MILAGE_RATES.INTERN_LTE_200:
      return 'Intern bis zu 200km'
    case MILAGE_RATES.INTERN_201_1000:
      return 'Intern 201-1.000km'
    case MILAGE_RATES.INTERN_1001_2000:
      return 'Intern 1.001-2.000km'
    case MILAGE_RATES.INTERN_GTE_2001:
      return 'Intern ab 2.001km'
    case MILAGE_RATES.EXTERN_LTE_200:
      return 'Extern bis zu 200km'
    case MILAGE_RATES.EXTERN_201_1000:
      return 'Extern 201-1.000km'
    case MILAGE_RATES.EXTERN_1001_2000:
      return 'Extern 1.001-2.000km'
    case MILAGE_RATES.EXTERN_GTE_2001:
      return 'Extern ab 2.001km'
    default:
      return 'Keine'
  }
}

function getBillStatusLabel(status: BILL_STATUS) {
  switch (status) {
    case BILL_STATUS.UNINVOICED:
      return 'Nicht gestellt'
    case BILL_STATUS.INVOICED:
      return 'Gestellt'
    case BILL_STATUS.PAID:
      return 'Bezahlt'
    default:
      return 'Unbekannt!!!'
  }
}

async function saveBill(
  booking: BookingDocument,
  bill: {
    milageStart: number
    milageEnd: number
    milage?: number
    rate: MILAGE_RATES
    additionalCosts?: AdditionalCosts[]
    status: BILL_STATUS
  }
): Promise<BillDocument> {
  const response = await fetch(`/api/booking/${booking.uuid}/bill/`, {
    method: booking.bill?._id ? 'PATCH' : 'POST',
    mode: 'cors',
    cache: 'no-cache',
    credentials: 'same-origin',
    headers: {
      'Content-Type': 'application/json',
    },
    referrerPolicy: 'no-referrer',
    body: JSON.stringify(bill),
  })
  return response.json()
}

export default function BillPage({
  booking: bookingProp,
}: {
  booking: BookingDocument
}) {
  const [booking, setBooking] = useState(bookingProp)
  const [milageStart, setMilageStart] = useState(booking.bill?.milageStart)
  const [milageEnd, setMilageEnd] = useState(booking.bill?.milageEnd)
  const [rate, setRate] = useState(
    booking.bill?.rate || MILAGE_RATES.EXTERN_LTE_200
  )
  const [status, setStatus] = useState(booking.bill?.status)
  const [storingInProgress, setStoringInProgress] = useState(false)
  const [storingError, setStoringError] = useState(null)
  const milage =
    (0 < milageStart && milageStart < milageEnd && milageEnd - milageStart) || 0
  const total =
    Math.round(milage && rate && milage * getMilageRateValue(rate) * 100) /
      100 || 0

  // in case the props change, update the internal state
  useEffect(() => setBooking(bookingProp), [bookingProp])

  const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault()
    setStoringInProgress(true)
    setStoringError(null)

    try {
      const bill = await saveBill(booking, {
        milageStart,
        milageEnd,
        milage,
        rate,
        status,
      })

      booking.bill = bill
      setBooking(booking)
    } catch (error) {
      setStoringError(error.toString())
      console.error('Failed to store booking', error)
    }
    setStoringInProgress(false)
  }

  return (
    <div className="mx-3 flex flex-col min-h-screen">
      <Header />
      <main className="flex-grow">
        <h2 className="text-3xl">Pfadi Bussle Buchung</h2>
        <form className="form" onSubmit={onSubmit}>
          <div>
            <strong>Buchungszeitraum:</strong>{' '}
            {dateFormatFrontend(new Date(booking.startDate))} -{' '}
            {dateFormatFrontend(new Date(booking.endDate))}
          </div>
          <div>
            <strong>Bucher:</strong> {booking.booker.name}
          </div>
          <div>
            <Input
              label="Anfangskilometer"
              name="milageStart"
              required
              value={milageStart}
              type="number"
              onChange={(e: React.ChangeEvent<React.ElementRef<'input'>>) =>
                setMilageStart(Number(e.target.value))
              }
            />
            <Input
              label="Endkilometer"
              name="milageEnd"
              required
              value={milageEnd}
              type="number"
              onChange={(e: React.ChangeEvent<React.ElementRef<'input'>>) =>
                setMilageEnd(Number(e.target.value))
              }
            />
            <Input label="Gefahren" name="milage" readOnly value={milage} />
            <div className="fsw">
              <div className="fs">
                <label className="flabel">Rate</label>
                <div className="relative">
                  <select
                    className="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
                    id="rate"
                    value={rate}
                    onChange={(
                      e: React.ChangeEvent<React.ElementRef<'select'>>
                    ) => {
                      setRate(e.target.value as MILAGE_RATES)
                    }}
                  >
                    {Object.values(MILAGE_RATES).map((rate) => {
                      return (
                        <option value={rate} key={rate}>
                          {getRateLabel(rate)} ({getMilageRateValue(rate)} EUR)
                        </option>
                      )
                    })}
                  </select>
                  <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
                    <svg
                      className="fill-current h-4 w-4"
                      xmlns="http://www.w3.org/2000/svg"
                      viewBox="0 0 20 20"
                    >
                      <path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" />
                    </svg>
                  </div>
                </div>
              </div>
            </div>
            <div className="fsw">
              <div className="fs">
                <label className="flabel">Status</label>
                <div className="relative">
                  <select
                    className="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
                    id="rate"
                    value={status}
                    onChange={(
                      e: React.ChangeEvent<React.ElementRef<'select'>>
                    ) => setStatus(e.target.value as BILL_STATUS)}
                  >
                    {Object.values(BILL_STATUS).map((status) => {
                      return (
                        <option value={status} key={status}>
                          {getBillStatusLabel(status)}
                        </option>
                      )
                    })}
                  </select>
                  <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
                    <svg
                      className="fill-current h-4 w-4"
                      xmlns="http://www.w3.org/2000/svg"
                      viewBox="0 0 20 20"
                    >
                      <path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" />
                    </svg>
                  </div>
                </div>
              </div>
            </div>

            <Input label="Summe" name="milage" readOnly value={total} />
          </div>
          {storingError && (
            <div className="error-message flex-grow">{storingError}</div>
          )}
          <button
            type="submit"
            className="btn btn-blue"
            disabled={storingInProgress}
          >
            Rechnung {booking.bill?._id ? 'Updaten' : 'Erstellen'}
          </button>
        </form>
      </main>

      <Footer />
    </div>
  )
}
