"use client";

import { DocumentIcon, TicketIcon, TrashIcon } from "@heroicons/react/24/outline";
import { Bill, BilledTo, BillingLocation } from "../lib/db-types";
import React, { FC, useEffect } from "react";
import { useFormState } from "react-dom";
import { updateOrAddBill } from "../lib/actions/billActions";
import Link from "next/link";
import { formatYearMonth } from "../lib/format";
import { decodeFromImage, DecodeResult, findDecodePdf417 } from "../lib/pdf/barcodeDecoder";
import { useLocale, useTranslations } from "next-intl";
import { Pdf417Barcode } from "./Pdf417Barcode";
import { InfoBox } from "./InfoBox";

// Next.js does not encode an utf-8 file name correctly when sending a form with a file attachment
// This is a workaround for that
const updateOrAddBillMiddleware = (locationId: string, billId: string | undefined, billYear: number | undefined, billMonth: number | undefined, prevState: any, formData: FormData) => {
    // URL encode the file name of the attachment so it is correctly sent to the server
    const billAttachment = formData.get('billAttachment') as File;
    formData.set('billAttachment', billAttachment, encodeURIComponent(billAttachment.name));
    return updateOrAddBill(locationId, billId, billYear, billMonth, prevState, formData);
}

export interface BillEditFormProps {
    location: BillingLocation,
    bill?: Bill,
}

export const BillEditForm: FC<BillEditFormProps> = ({ location, bill }) => {

    const t = useTranslations("bill-edit-form");
    const locale = useLocale();

    const { _id: billID, name, paid, billedTo = BilledTo.Tenant, attachment, notes, payedAmount: initialPayedAmount, proofOfPayment } = bill ?? { _id: undefined, name: "", paid: false, notes: "" };

    const { yearMonth: { year: billYear, month: billMonth }, _id: locationID, proofOfPaymentType } = location;

    const initialState = { message: null, errors: {} };

    const handleAction = updateOrAddBillMiddleware.bind(null, locationID, billID, billYear, billMonth);

    const [isScanningPDF, setIsScanningPDF] = React.useState<boolean>(false);
    const [state, dispatch] = useFormState(handleAction, initialState);
    const [isPaid, setIsPaid] = React.useState<boolean>(paid);
    const [billedToValue, setBilledToValue] = React.useState<BilledTo>(billedTo);
    const [payedAmount, setPayedAmount] = React.useState<string>(initialPayedAmount ? `${initialPayedAmount / 100}` : "");

    // legacy support - to be removed
    const [hub3aText, setHub3aText] = React.useState<string | undefined>(bill?.hub3aText);
    const [barcodeResults, setBarcodeResults] = React.useState<Array<DecodeResult> | null>(null);

    useEffect(() => {
        // migrating the legacy `barcodeImage` field to `hub3aText`
        // by converting it to `hub3aText`
        if (!hub3aText && bill?.barcodeImage) {
            decodeFromImage(bill.barcodeImage).then(results => {
                if (results) {
                    const {
                        hub3aText: decodedHub3aText,
                    } = results;

                    setHub3aText(decodedHub3aText);
                }
            }).catch(error => {
                console.error('Failed to migrate barcodeImage to hub3aText:', error);
            });
        }
    }, [bill?.barcodeImage, hub3aText]);


    const billedTo_handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
        setBilledToValue(event.target.value as BilledTo);
    }

    const billPaid_handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setIsPaid(event.target.checked);
    }

    const payedAmount_handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setPayedAmount(event.target.value);
    }

    const billAttachment_handleChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
        setIsScanningPDF(true);

        setPayedAmount("");
        setBarcodeResults(null);

        const results = await findDecodePdf417(event);

        if (results && results.length > 0) {

            if (results.length === 1) {
                const {
                    hub3aText,
                    billInfo
                } = results[0];

                setPayedAmount(`${billInfo.amount / 100}`);
                setHub3aText(hub3aText);
            } else {
                setPayedAmount("");
                setBarcodeResults(results);
                setHub3aText(undefined);
            }
        }

        setIsScanningPDF(false);
    }

    const handleBarcodeSelectClick = (result: DecodeResult) => {
        setPayedAmount(`${result.billInfo.amount / 100}`);
        setHub3aText(result.hub3aText);
        setBarcodeResults(null);
    }

    return (
        <div className="card card-compact card-bordered bg-base-100 shadow-s">
            <div className="card-body">
                <h2 className="card-title">{`${formatYearMonth(location.yearMonth)} ${location.name}`}</h2>
                <form action={dispatch}>
                    {
                        // don't show the delete button if we are adding a new bill
                        bill ?
                            <Link href={`/${locale}/home/bill/${locationID}-${billID}/delete/`} data-tip={t("delete-tooltip")}>
                                <TrashIcon className="h-[1em] w-[1em] absolute cursor-pointer text-error bottom-5 right-4 text-2xl" />
                            </Link> : null
                    }

                    <input id="billName" name="billName" type="text" placeholder={t("bill-name-placeholder")} className="input input-bordered w-full" defaultValue={name} required />
                    <div id="status-error" aria-live="polite" aria-atomic="true">
                        {state.errors?.billName &&
                            state.errors.billName.map((error: string) => (
                                <p className="mt-2 text-sm text-red-500" key={error}>
                                    {error}
                                </p>
                            ))}
                    </div>
                    {
                        // <textarea className="textarea textarea-bordered my-1 w-full max-w-sm block" placeholder="Opis" value="Pričuva, Voda, Smeće"></textarea>

                        attachment ?
                            <Link href={`/attachment/${locationID}-${billID}/`} target="_blank" className='text-center w-full max-w-[20em] text-nowrap truncate inline-block mt-4'>
                                <DocumentIcon className="h-[1em] w-[1em] text-2xl inline-block mr-1" />
                                {decodeURIComponent(attachment.fileName)}
                            </Link>
                            : null
                    }
                    <div className="flex">
                        <input id="billAttachment" name="billAttachment" type="file" className="file-input file-input-bordered grow file-input-s my-2 block max-w-[17em] md:max-w-[80em] break-words" onChange={billAttachment_handleChange} />
                    </div>
                    {
                        isScanningPDF &&
                        <div className="flex flex-row items-center w-full mt-2">
                            <div className="loading loading-spinner loading-m mr-2"></div>
                            <span>{t("scanning-pdf")}</span>
                        </div>
                    }
                    {
                        // if multiple results are found, show them as a list
                        // and notify the user to select the correct one
                        barcodeResults && barcodeResults.length > 0 &&
                        <>
                            <div className="flex mt-2 ml-2">
                                <label className="label-text max-w-xs break-words">{t("multiple-barcode-results-notification")}</label>
                            </div>
                            <div className="flex">
                                <label className="label grow pt-0 ml-3">
                                    <ul className="list-none">
                                        {barcodeResults.map((result, index) => (
                                            <li key={index} className="cursor-pointer mt-3" onClick={() => handleBarcodeSelectClick(result)}>
                                                👉 {result.billInfo.description}
                                            </li>
                                        ))}
                                    </ul>
                                </label>
                            </div>
                        </>
                    }
                    <div id="status-error" aria-live="polite" aria-atomic="true">
                        {state.errors?.billAttachment &&
                            state.errors.billAttachment.map((error: string) => (
                                <p className="mt-2 text-sm text-red-500" key={error}>
                                    {error}
                                </p>
                            ))}
                    </div>
                    <div className="flex">
                        <div className="form-control flex-row">
                            <label className="cursor-pointer label align-middle">
                                <span className="label-text mr-[1em]">{t("paid-checkbox")}</span>
                                <input id="billPaid" name="billPaid" type="checkbox" className="toggle toggle-success" defaultChecked={paid} onChange={billPaid_handleChange} />
                            </label>
                        </div>
                        <div className="form-control grow">
                            <label className="cursor-pointer label grow">
                                <span className="label-text mx-[1em]">{t("payed-amount")}</span>
                                <input type="text" id="payedAmount" name="payedAmount" className="input input-bordered text-right w-[5em] grow" placeholder="0.00" value={payedAmount} onFocus={e => e.target.select()} onChange={payedAmount_handleChange} />
                            </label>
                        </div>
                    </div>
                    <div id="status-error" aria-live="polite" aria-atomic="true">
                        {state.errors?.payedAmount &&
                            state.errors.payedAmount.map((error: string) => (
                                <p className="mt-2 text-sm text-red-500" key={error}>
                                    {error}
                                </p>
                            ))}
                    </div>

                    <input type="hidden" name="hub3aText" value={hub3aText} />
                    {
                        hub3aText ?
                            <div className="form-control p-1">
                                <label className="label p-2 grow bg-white border border-gray-300 rounded-box justify-center">
                                    <Pdf417Barcode hub3aText={hub3aText} />
                                </label>
                                <p className="text-xs my-1">{t.rich('barcode-disclaimer', { br: () => <br /> })}</p>
                            </div> : null
                    }
                    <textarea id="billNotes" name="billNotes" className="textarea textarea-bordered my-2 max-w-lg w-full block" placeholder={t("notes-placeholder")} defaultValue={notes ?? ''}></textarea>
                    <div id="status-error" aria-live="polite" aria-atomic="true">
                        {state.errors?.billNotes &&
                            state.errors.billNotes.map((error: string) => (
                                <p className="mt-2 text-sm text-red-500" key={error}>
                                    {error}
                                </p>
                            ))}
                    </div>

                    <fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 mt-4">
                        <InfoBox>{t("billed-to-info")}</InfoBox>
                        <legend className="fieldset-legend font-semibold uppercase">{t("billed-to-legend")}</legend>
                        <select className="select select-bordered w-full" name="billedTo" defaultValue={billedToValue} onChange={billedTo_handleChange}>
                            <option value={BilledTo.Tenant}>{t("billed-to-tenant-option")}</option>
                            <option value={BilledTo.Landlord}>{t("billed-to-landlord-option")}</option>
                        </select>
                    </fieldset>

                    {
                        // IF proof of payment type is "per-bill" and proof of payment was uploaded
                        proofOfPaymentType === "per-bill" && proofOfPayment?.uploadedAt ?
                        <fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-2 pt-0 mt-3 mb-3">
                            <legend className="fieldset-legend font-semibold uppercase">{t("upload-proof-of-payment-legend")}</legend>
                            {
                                    // IF file name is available, show link to download
                                    // ELSE it's not available that means that the uploaded file was purged by housekeeping
                                    // -> don't show anything
                                    proofOfPayment.fileName ? (
                                        <div className="mt-3 ml-[-.5rem]">
                                            <Link
                                                href={`/share/proof-of-payment/per-bill/${locationID}-${billID}/`}
                                                target="_blank"
                                                className='text-center w-full max-w-[20rem] text-nowrap truncate inline-block'
                                            >
                                                <TicketIcon className="h-[1em] w-[1em] text-2xl inline-block mr-1 text-teal-500" />
                                                {decodeURIComponent(proofOfPayment.fileName)}
                                            </Link>
                                        </div>
                                    ) : null
                            }
                        </fieldset> : null
                    }

                    {/* Show toggle only when adding a new bill (not editing) */}
                    {!bill && (
                        <div className="form-control">
                            <label className="label cursor-pointer">
                                <span className="label-text">{t("add-to-subsequent-months")}</span>
                                <input type="checkbox" name="addToSubsequentMonths" className="toggle toggle-primary" />
                            </label>
                        </div>
                    )}

                    <div className="pt-4">
                        <button type="submit" className="btn btn-primary">{t("save-button")}</button>
                        <Link className="btn btn-neutral ml-3" href={`/home?year=${billYear}&month=${billMonth}`}>{t("cancel-button")}</Link>
                    </div>

                    <div id="status-error" aria-live="polite" aria-atomic="true">
                        {state.message &&
                            <p className="mt-2 text-sm text-red-500">
                                {state.message}
                            </p>
                        }
                    </div>

                </form>
            </div>
        </div>);
}