import React, {useEffect, useState} from 'react'
import axios from 'axios'
import {Head, usePage} from '@inertiajs/react'
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
import {
    faArrowLeft,
    faQuestionCircle,
    faBoxOpen,
    faClipboardList,
    faCubes,
    faPlus, faBarcode,
} from '@fortawesome/free-solid-svg-icons'
import {toast, Toaster} from 'react-hot-toast'

import Tile from '../Components/Tile'
import TileLayout from '../Components/TileLayout'
import ModalPDA from '../Components/ModalPDA'

// your extracted modal forms:
import SetStockModal from '../Components/modals/SetStockModal'
import OtherReplacementModal from '../Components/modals/OtherReplacementModal'
import CountStockModal from '../Components/modals/CountStockModal'
import {Batch} from "@/interfaces/interfaces";
import {StockBatch, StockPosition, StockSection} from "@/types";
import BatchInfoModal from "@/Components/modals/BatchInfoModal";
import {downloadBatchBarcode} from "@/functions/functions"
import EditStockSections from "@/Components/modals/EditStockSections";
import MoveSectionModal from "@/Components/modals/MoveSectionModal";
import ChangeCountModal from "@/Components/modals/ChangeCountModal";

import error_scanner_sound from "@/sounds/error_scanner.mp3";
import SetStockModalFromTemp from "@/Components/modals/SetStockModalFromTemp";

type Role = 'Expedice' | 'Skladnik'

// actions per role
const roleActions: Record<Role, string[]> = {
    Expedice: ['stockSectionScanned', 'labelScanned'],
    Skladnik: ['batchScan', 'stockScan'],
}

// configuration for each tile: either opens a modal (modalKey),
// or performs an API call (onClick)
type TileConfig = {
    title: string
    icon: any
    modalKey?: ModalKey
    onClick?: () => void
}


type ModalKey =
    'setStock'
    | 'setStockFromTemp'
    | 'otherReplacement'
    | 'countStock'
    | 'batchInfo'
    | 'editStock'
    | 'moveStock'
    | 'changeCount'
    | null

type PdaViewProps = { closeParent: () => void };

export default function PdaView({closeParent}: PdaViewProps) {

    const tilesConfig: Record<Role, Record<string, TileConfig[]>> = {
        Expedice: {
            stockSectionScanned: [
                {title: 'Not Present', icon: faBoxOpen, onClick: () => toast('Not Present clicked')},
                {title: 'Na pozici je jiny ovladac', icon: faBoxOpen, onClick: () => toast('Not Present clicked')},
                {
                    title: 'Present but Shouldn’t',
                    icon: faClipboardList,
                    onClick: async () => {
                        // example direct axios call
                        try {
                            await axios.post('/api/presence-error', {}, {withCredentials: true})
                            toast.success('Reported!')
                        } catch {
                            toast.error('Failed to report')
                        }
                    },
                },
                {title: 'Other Replacement (na test/one time)', icon: faPlus, modalKey: 'otherReplacement'},
                {title: 'Pridej vazbu na jiny ovladac', icon: faPlus, onClick: () => toast('Batch Info clicked')},
                {
                    title: 'Pridej docasnou vazbu (nez prijde jine zbozi, i casove omezene, nejnizsi priorita)',
                    icon: faPlus,
                    onClick: () => toast('Batch Info clicked')
                },
                {title: 'Doplnit zbozi / dej vic kusu', icon: faPlus, onClick: () => toast('Batch Info clicked')},
                {
                    title: 'Report - chci zmenit pozici(bliz / dal od expedice)',
                    icon: faPlus,
                    onClick: () => toast('Batch Info clicked')
                },
                {
                    title: 'Pultovy prodej',
                    icon: faPlus,
                    onClick: () => toast('- naskenuju na webu / naskenuju na skladovem miste, obj. se udela automaticky, zakaznik si muze v rohu na PC vyplnit osobni udaje na special formulari - pak customera prida obsluha do obj')
                },
            ],
            labelScanned: [
                {title: 'Info', icon: faClipboardList, onClick: () => toast('Batch Info clicked')},
            ]
        },
        Skladnik: {
            batchScan: [
                {title: 'Batch Info', icon: faClipboardList, modalKey: 'batchInfo'},
                {title: 'Set Stock', icon: faCubes, modalKey: 'setStock'},
                {title: 'Count Stock', icon: faPlus, modalKey: 'countStock'},
                {
                    title: 'Stitkovani (male stitky)',
                    icon: faClipboardList,
                    onClick: () => toast('Stitkovani (male stitky)')
                },
                {
                    title: 'Tisk QR kod na krabice',
                    icon: faClipboardList,
                    onClick: () => downloadBatchBarcode(selectedBatch?.id)
                },
            ],
            stockScan: [
                {title: 'Info', icon: faClipboardList, onClick: () => toast('Batch Info clicked')},
                {title: 'Set Stock', icon: faCubes, modalKey: 'setStockFromTemp'},
                {
                    title: 'Zmena skladoveho mista (i presun jen casti kusu)',
                    icon: faClipboardList,
                    modalKey: 'moveStock'
                },
                {title: 'Uprava skladoveho mista (mene sekci, apod)', icon: faClipboardList, modalKey: 'editStock'},
                {title: 'Zmena poctu', icon: faClipboardList, modalKey: 'changeCount'},
                {
                    title: 'Discard (odebrat ze skladoveho mista / posilame zpet)',
                    icon: faClipboardList,
                    onClick: () => toast('Batch Info clicked')
                },
            ],
            others: [
                {title: 'Nove skladove misto', icon: faClipboardList, onClick: () => toast('Batch Info clicked')},
            ]
        },
    }

    const {
        auth: {user},
    } = usePage<{ auth: { user: { role: string } } }>().props

    const [role, setRole] = React.useState<Role>(
        user.role === 'admin' ? 'Expedice' : (user.role as Role)
    )
    const [action, setAction] = React.useState<string>('')
    const [activeModal, setActiveModal] = React.useState<ModalKey>(null)

    const isAdmin = true
    // const isAdmin = user.role === 'admin'
    const tabs: Role[] = ['Expedice', 'Skladnik']

    const [selectedSerial, setSelectedSerial] = useState(null);

    const selectedSectionRef = React.useRef<StockSection | null>(null)
    const selectedPositionRef = React.useRef<StockPosition | null>(null)

    const closeModal = () =>  {
        setActiveModal(null);
        if(selectedBatch) {
            refetchData();
        }

    }


    const refetchData = async () => {

        try {
            const res = await axios.get('/api/stockBatches/' + selectedBatch?.id);
            console.log(res.data);
            setSelectedBatch(res.data.batch);
        } catch {
            toast.error('Unable to reload batch data');
        }

    }

    // const closeModal = () => {
    //     setActiveModal(null)
    //     setPrevPosition(null)
    //     setPrevSection(null)
    //     setSelectedPosition(null)
    //     setSelectedSection(null)
    // }

    const wrapOnClick = (orig?: () => void) => {
        return () => {
            if (orig) orig();
            // after the action, close the PDA modal:
            closeParent();
        };
    };

    const [selectedBatch, setSelectedBatch] = React.useState<StockBatch>();
    const [selectedPosition, setSelectedPosition] = React.useState<StockPosition>();
    const [selectedSection, setSelectedSection] = React.useState<StockSection>();

    const [prevPosition, setPrevPosition] = useState<StockPosition | null>(null)
    const [prevSection, setPrevSection] = useState<StockSection | null>(null)

    useEffect(() => {
        // fetchBatches();
        // fetchPosition();
        initScanner();
    }, []);

    const initScanner = () => {
        // run once on mount
        (async () => {
            // see if we already have permission for any ports
            const ports = await navigator.serial.getPorts();
            console.log("ports", ports);
            if (ports.length > 0) {
                // pick the first (or filter by vendorId/productId)
                const port = ports[0];
                setSelectedSerial(port);
                // now you can immediately open it:
                connectToScanner(port);
            }
        })();
    };

    const handlePortRequest = async () => {
        try {
            const port = await navigator.serial.requestPort();  // <-- user gesture!
            setSelectedSerial(port);
            await connectToScanner(port);
        } catch (err) {
            console.error("User cancelled or error:", err);
        }
    };


    const connectToScanner = async (port) => {
        try {
            // Request a port and open a connection
            console.log(selectedSerial);
            await port.open({baudRate: 9600});

            // setIsConnected(true);

            const reader = port.readable.getReader();
            const decoder = new TextDecoder();
            let buffer = ""; // Buffer to accumulate chunks

            while (true) {
                const {value, done} = await reader.read();
                if (done) {
                    // Close the stream
                    reader.releaseLock();
                    break;
                }
                if (value) {
                    // Decode and append to the buffer
                    buffer += decoder.decode(value, {stream: true});
                    // Process messages split by newline or other delimiter
                    let lines = buffer.split(/[\n\t]/);
                    buffer = lines.pop(); // Keep the last incomplete chunk

                    for (const line of lines) {
                        const trimmedLine = line.trim();
                        sendToBackend(trimmedLine);
                    }
                }
            }
        } catch (error) {
            console.error("Error connecting to scanner:", error);
        }
    };


    const sendToBackend = async (scannedData: string) => {
        const audioError = document.getElementById("audio_error") as HTMLAudioElement;
        audioError.volume = 1.0;

        console.log("scannedData", scannedData);

        // 1) Parse JSON
        let payload: { barcode_type: string; payload: { id: number } };
        try {
            payload = JSON.parse(scannedData);
        } catch (err) {
            toast.error("Invalid barcode data");
            audioError.play();
            return;
        }

        const {barcode_type, payload: inner} = payload;
        const {id} = inner;

        // 2) Call your API
        try {
            const response = await axios.post("/api/pda/barcodeScan", {
                barcode_type,
                payload: {id},
            });

            const {success, data, message, error} = response.data;

            console.log("response", data);

            if (!success) {
                // Laravel sends 200+ success=false for business errors, or 4xx/5xx for validation/not-found/etc
                toast.error(
                    // Validation errors come back as an object of messages
                    Array.isArray(message)
                        ? Object.values(message).flat().join("; ")
                        : message || "Scan failed"
                );
                audioError.play();
                return;
            }

            // 3) On success, data will be the model (batch/section/position/label) or undefined for carrier_scanned
            switch (barcode_type) {
                case "stock_batch":
                    setAction("batchScan");
                    setSelectedBatch(data);
                    // you now have the full batch record in `data`
                    break;

                case "stock_section":
                    setAction("stockScan");

                    // the “from” section is whatever was last in the ref
                    const oldSection = selectedSectionRef.current
                    // const oldPosition = selectedPositionRef.current

                    // the “to” section is the data you just fetched
                    const newSection = data

                    setPrevSection(oldSection)
                    // setPrevPosition(oldPosition)

                    setSelectedSection(newSection)
                    // setSelectedPosition(newSection.position)

                    console.log("FROM (prevSection):", oldSection)
                    console.log("  TO   (selectedSection):", newSection)
                    break

                case "stock_position":

                    setPrevPosition(selectedPosition || null);

                    setAction("stockScan");
                    setSelectedPosition(data);
                    break;

                case "label_scanned":
                    setAction("labelScan");
                    // perhaps `data.product` or `data.batch` are in here if you need them
                    break;

                case "carrier_scanned":
                    setAction("carrierScan");
                    // no data field returned, but success=true means it worked
                    break;

                default:
                    // validator already prevents this, but just in case
                    toast.error(`Unknown barcode type: ${barcode_type}`);
                    audioError.play();
            }
        } catch (err: any) {
            // 4xx / 5xx HTTP errors, or network failures
            if (err.response) {
                // Laravel ValidationException → 422
                if (err.response.status === 422) {
                    const errors = err.response.data.message;
                    toast.error(
                        Array.isArray(errors)
                            ? errors.join("; ")
                            : typeof errors === "object"
                                ? Object.values(errors).flat().join("; ")
                                : errors
                    );
                }
                // ModelNotFound → 404
                else if (err.response.status === 404) {
                    toast.error(err.response.data.message || "Record not found");
                }
                // Any other server error
                else {
                    toast.error(err.response.data.message || "Server error");
                }
            } else {
                // network / CORS / timeout
                toast.error("Network error");
            }
            console.error("sendToBackend error:", err);
            audioError.play();
        }
    };

    useEffect(() => {
        selectedSectionRef.current = selectedSection ?? null
    }, [selectedSection])

    useEffect(() => {
        selectedPositionRef.current = selectedPosition ?? null
    }, [selectedPosition])


    return (
        <>
            <Head title="PDA View"/>
            <audio id="audio_error" src={error_scanner_sound}>

            </audio>

            {/* Top bar */}
            <div className="flex justify-between items-center bg-base-100 p-4 shadow">

                <a className="link" href={route('dashboard')}><FontAwesomeIcon icon={faArrowLeft}/> Back</a>
                {!selectedSerial && (
                    <button className="btn btn-ghost" onClick={handlePortRequest}>
                        <FontAwesomeIcon icon={faBarcode}/>
                    </button>
                )}
                <button className="btn btn-ghost">
                    <FontAwesomeIcon icon={faQuestionCircle}/> Help
                </button>

            </div>

            {/* Admin tabs */}
            {isAdmin && (
                <div className="tabs justify-center bg-base-100">
                    {tabs.map((r) => (
                        <button
                            key={r}
                            className={`tab ${role === r ? 'tab-active' : ''}`}
                            onClick={() => {
                                setRole(r)
                                setAction('')
                            }}
                        >
                            {r}
                        </button>
                    ))}
                </div>
            )}

            {/* Action selectors */}
            <div className="flex justify-center space-x-4 space-y-4 sm:space-y-0 p-4 sm:flex-nowrap flex-wrap">
                {[...(roleActions[role] || []), 'clear'].map((act) => (
                    <button
                        key={act}
                        className="btn btn-outline"
                        onClick={() => {
                            const newAct = act === 'clear' ? '' : act
                            setAction(newAct)
                            toast(`Action set to ${newAct || 'none'}`)
                        }}
                    >
                        {act === 'clear' ? 'Clear Action' : act}
                    </button>
                ))}
            </div>

            {/* Tiles */}
            <TileLayout>
                {action && (() => {
                    // grab the base array
                    let tiles = tilesConfig[role][action] || []

                    // if we're stock-scanning but the position isn’t temporary, hide “Set Stock”
                    if (action === 'stockScan' && !selectedPosition?.temporary) {
                        tiles = tiles.filter(tile => tile.modalKey !== 'setStockFromTemp')
                    }

                    // render the filtered list
                    return tiles.map(({ title, icon, onClick, modalKey }) => (
                        <Tile
                            key={title}
                            title={title}
                            icon={icon}
                            onClick={() => {
                                if (modalKey) setActiveModal(modalKey)
                                else if (onClick) onClick()
                            }}
                        />
                    ))
                })()}
            </TileLayout>

            {/* Single Modal */}
            <ModalPDA isOpen={activeModal !== null} onClose={closeModal}>
                {activeModal === 'batchInfo' && <BatchInfoModal onClose={closeModal} selectedBatch={selectedBatch}/>}
                {activeModal === 'setStock' &&
                    <SetStockModal onClose={closeModal} selectedBatch={selectedBatch} selectedSection={selectedSection}
                                   selectedPosition={selectedPosition}/>}
                {activeModal === 'setStockFromTemp' &&
                    <SetStockModalFromTemp onClose={closeModal} selectedSection={selectedSection}
                                   selectedPosition={selectedPosition}/>}
                {activeModal === 'otherReplacement' && <OtherReplacementModal onClose={closeModal}/>}
                {activeModal === 'countStock' && <CountStockModal onClose={closeModal} selectedBatch={selectedBatch}/>}
                {activeModal === 'editStock' &&
                    <EditStockSections onClose={closeModal} selectedPosition={selectedPosition}/>}
                {activeModal === 'moveStock' &&
                    <MoveSectionModal onClose={closeModal}
                                      fromPosition={prevPosition}
                                      fromSection={prevSection}
                                      toPosition={selectedPosition}
                                      toSection={selectedSection}/>
                }
                {activeModal === 'changeCount' &&
                    <ChangeCountModal onClose={closeModal} selectedPosition={selectedPosition}/>}
            </ModalPDA>

            <Toaster position="top-right"/>
        </>
    )
}
