import React, { useState } from 'react';
import { Button } from "@/components/ui/button"
import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuGroup,
    DropdownMenuItem,
    DropdownMenuShortcut,
    DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"

import { Eye, EyeClosed } from "lucide-react"
import {
    Tooltip,
    TooltipContent,
    TooltipTrigger,
} from "@/components/ui/tooltip"


import { Button } from "@/components/ui/button"


import React from "react"
import {
    Table,
    TableHeader,
    TableBody,
    TableRow,
    TableHead,
    TableCell,
} from "@/components/ui/table"

function parseTable(lines, startIndex) {
    const headerLine = lines[startIndex]
    const separatorLine = lines[startIndex + 1]

    if (!separatorLine || !separatorLine.match(/^\s*\|[-\s|]+\|\s*$/)) {
        return null
    }

    const headers = headerLine
        .split("|")
        .slice(1, -1)
        .map(h => h.trim())

    const rows = []
    let i = startIndex + 2

    while (i < lines.length && lines[i].includes("|")) {
        const cells = lines[i]
            .split("|")
            .slice(1, -1)
            .map(c => c.trim())
        rows.push(cells)
        i++
    }

    return {
        table: { headers, rows },
        nextIndex: i,
    }
}

export function Markdown({ children, dic, show }) {
    const [localMessage, setLocalMessage] = useState(children);
    const [open, setOpen] = useState(false);
    const [position, setPosition] = useState({ x: 0, y: 0 });
    const [selectionData, setSelectionData] = useState(null);
    const lines = children.split("\n")
    const elements = []
    let i = 0

    const handleMouseUp = () => {

        const selection = window.getSelection();

        // 1. Check basic validity
        if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
            // If just a click (collapsed), we assume menu shouldn't open or should close
            // But we don't want to close immediately if clicking inside the menu, handled by DropdownMenu logic
            return;
        }

        // 2. Expand Selection to Word Boundaries
        const anchorNode = selection.anchorNode;
        const focusNode = selection.focusNode;

        // Only support single text node selection for simplicity to map back to data-index
        if (anchorNode !== focusNode || anchorNode.nodeType !== 3) {
            setOpen(false);
            return;
        }

        const textContent = anchorNode.textContent;
        let start = Math.min(selection.anchorOffset, selection.focusOffset);
        let end = Math.max(selection.anchorOffset, selection.focusOffset);

        // Expand left
        while (start > 0 && /\S/.test(textContent[start - 1])) {
            start--;
        }
        // Expand right
        while (end < textContent.length && /\S/.test(textContent[end])) {
            end++;
        }

        // Update visual selection
        const newRange = document.createRange();
        newRange.setStart(anchorNode, start);
        newRange.setEnd(anchorNode, end);
        selection.removeAllRanges();
        selection.addRange(newRange);


        const newText = textContent.slice(start, end);
        if (!newText.trim()) return;

        // 3. Validation Logic
        // Check 1: Less than 4 words
        const words = newText.split(/\s+/);
        if (words.length >= 4) {
            setOpen(false);
            return;
        }

        // Check 2: Does not contain highlighted word (brackets)
        if (newText.includes('[') || newText.includes(']')) {
            setOpen(false);
            return;
        }

        // Check 3: Check if selection is inside a Badge
        const parentElement = anchorNode.parentElement;
        if (parentElement.closest('.bg-pii')) {
            setOpen(false);
            return;
        }

        // Identify Part Index
        const partIndex = parseInt(parentElement.getAttribute('data-index'), 10);
        // if (isNaN(partIndex)) {
        //     setOpen(false);
        //     return;
        // }

        const rect = newRange.getBoundingClientRect();
        setPosition({
            x: rect.left,
            y: rect.bottom
        });
        setSelectionData({
            partIndex,
            start,
            end,
            text: newText
        });
        setOpen(true);
    };

    const handleAnonymize = () => {
        if (!selectionData) return;
        const { partIndex, start, end, text } = selectionData;

        // Split by brackets to reconstruct parts array as seen in render
        const parts = localMessage.split(/(\[[^\]]+\])/g);

        if (parts[partIndex] === undefined) return;

        const originalPart = parts[partIndex];
        const newPart = originalPart.substring(0, start) + `[ANONYME_${text}]` + originalPart.substring(end);

        parts[partIndex] = newPart;
        const newMessage = parts.join('');

        setLocalMessage(newMessage);
        setOpen(false);
        // Clear selection
        window.getSelection().removeAllRanges();
    };

    while (i < lines.length) {
        const line = lines[i]

        // HEADERS
        const headerMatch = line.match(/^(#{1,6})\s+(.*)$/)
        if (headerMatch) {
            const level = headerMatch[1].length
            const text = headerMatch[2]
            const Tag = `h${level}`

            elements.push(
                <Tag key={i} className="mt-4 mb-2 font-semibold">
                    {renderInline(text, dic, show)}
                </Tag>
            )
            i++
            continue
        }

        // TABLE
        if (line.trim().startsWith("|")) {
            const parsed = parseTable(lines, i)
            if (parsed) {
                const { headers, rows } = parsed.table

                elements.push(
                    <Table key={i} className="my-4">
                        <TableHeader>
                            <TableRow>
                                {headers.map((h, idx) => (
                                    <TableHead key={idx}>
                                        {renderInline(h, dic, show)}
                                    </TableHead>
                                ))}
                            </TableRow>
                        </TableHeader>
                        <TableBody>
                            {rows.map((row, rIdx) => (
                                <TableRow key={rIdx}>
                                    {row.map((cell, cIdx) => (
                                        <TableCell key={cIdx}>
                                            {renderInline(cell, dic, show)}
                                        </TableCell>
                                    ))}
                                </TableRow>
                            ))}
                        </TableBody>
                    </Table>
                )

                i = parsed.nextIndex
                continue
            }
        }

        // PARAGRAPH
        if (line.trim() !== "") {
            elements.push(
                <p key={i} className="mb-2">
                    {renderInline(line, dic, show)}
                </p>
            )
        }

        i++
    }

    return (
        <div onMouseUp={handleMouseUp}>
            <div className="relative bg-accent rounded-3xl px-5 py-2.5 user-message flex-grow-0">
                <p className="leading-[1.75] whitespace-pre-wrap">{elements}</p>

                <DropdownMenu open={open} onOpenChange={setOpen}>
                    <DropdownMenuTrigger asChild>
                        <div
                            style={{
                                position: 'fixed',
                                top: position.y,
                                left: position.x,
                                width: '1px',
                                height: '1px',
                                visibility: 'hidden',
                                pointerEvents: 'none'
                            }}
                        />
                    </DropdownMenuTrigger>
                    <DropdownMenuContent align="start">
                        <DropdownMenuGroup>
                            <DropdownMenuItem onSelect={handleAnonymize}>
                                Anonymiser
                            </DropdownMenuItem>
                        </DropdownMenuGroup>
                    </DropdownMenuContent>
                </DropdownMenu>
            </div>
        </div>
    )
}

function parseInlineText(text) {
    const tokens = []
    let i = 0

    while (i < text.length) {
        // CODE `
        if (text[i] === "`") {
            const end = text.indexOf("`", i + 1)
            if (end !== -1) {
                tokens.push({ type: "code", value: text.slice(i + 1, end) })
                i = end + 1
                continue
            }
        }

        // BOLD **
        if (text.slice(i, i + 2) === "**") {
            const end = text.indexOf("**", i + 2)
            if (end !== -1) {
                tokens.push({ type: "bold", value: text.slice(i + 2, end) })
                i = end + 2
                continue
            }
        }

        // ITALIC *
        if (text[i] === "*") {
            const end = text.indexOf("*", i + 1)
            if (end !== -1) {
                tokens.push({ type: "italic", value: text.slice(i + 1, end) })
                i = end + 1
                continue
            }
        }

        // TEXT
        let j = i
        while (
            j < text.length &&
            text[j] !== "`" &&
            text[j] !== "*"
        ) {
            j++
        }

        tokens.push({ type: "text", value: text.slice(i, j) })
        i = j
    }

    return tokens
}


function renderInline(text, dic, show) {
    const parts = text.split(/(\[[^\]]+\])/g)

    return parts.map((part, index) => {
        // PII
        const match = part.match(/^\[(\w+)_(.*?)\]$/)
        if (match && dic[match[2]]) {
            return show ? (
                <Badge
                    key={index}
                    className="bg-pii text-blue-800 rounded-full px-2 py-1 mx-1"
                >
                    {dic[match[2]].value}
                </Badge>
            ) : (
                <Tooltip key={index}>
                    <TooltipTrigger asChild>
                        <Badge
                            key={index}
                            className="bg-pii text-blue-800 rounded-full px-2 py-1 mx-1 blur-sm"
                        >
                            {dic[match[2]].value}
                        </Badge>
                        {/* <span className="bg-pii px-1 rounded cursor-pointer blur-sm">
                            {/* {part.toUpperCase()} */}
                        {/* {dic[match[2]].value} */}
                        {/* </span> */}
                    </TooltipTrigger>
                    <TooltipContent>
                        <p>{dic[match[2]].value}</p>
                    </TooltipContent>
                </Tooltip >
            )
        }

        // TEXTE NORMAL → inline markdown
        const tokens = parseInlineText(part)

        return (
            <span key={index} data-index={index}>
                {tokens.map((t, i) => {
                    if (t.type === "bold") {
                        return <strong key={i}>{t.value}</strong>
                    }
                    if (t.type === "italic") {
                        return <em key={i}>{t.value}</em>
                    }
                    if (t.type === "code") {
                        return (
                            <code
                                key={i}
                                className="px-1 py-0.5 rounded bg-muted text-sm"
                            >
                                {t.value}
                            </code>
                        )
                    }
                    return <span key={i}>{t.value}</span>
                })}
            </span>
        )
    })
}


const Badge = ({ children, className }) => (
    <span className={` py-0.5 transition-colors text-main-700 ${className}`}>
        {children}
    </span>
);


function MessageWithHighlight({ message, dic, show }) {
    if (!message) return null;

    const [localMessage, setLocalMessage] = useState(message);
    const [open, setOpen] = useState(false);
    const [position, setPosition] = useState({ x: 0, y: 0 });
    const [selectionData, setSelectionData] = useState(null);

    const handleMouseUp = () => {
        const selection = window.getSelection();

        // 1. Check basic validity
        if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
            // If just a click (collapsed), we assume menu shouldn't open or should close
            // But we don't want to close immediately if clicking inside the menu, handled by DropdownMenu logic
            return;
        }

        // 2. Expand Selection to Word Boundaries
        const anchorNode = selection.anchorNode;
        const focusNode = selection.focusNode;

        // Only support single text node selection for simplicity to map back to data-index
        if (anchorNode !== focusNode || anchorNode.nodeType !== 3) {
            setOpen(false);
            return;
        }

        const textContent = anchorNode.textContent;
        let start = Math.min(selection.anchorOffset, selection.focusOffset);
        let end = Math.max(selection.anchorOffset, selection.focusOffset);

        // Expand left
        while (start > 0 && /\S/.test(textContent[start - 1])) {
            start--;
        }
        // Expand right
        while (end < textContent.length && /\S/.test(textContent[end])) {
            end++;
        }

        // Update visual selection
        const newRange = document.createRange();
        newRange.setStart(anchorNode, start);
        newRange.setEnd(anchorNode, end);
        selection.removeAllRanges();
        selection.addRange(newRange);

        const newText = textContent.slice(start, end);
        if (!newText.trim()) return;

        // 3. Validation Logic
        // Check 1: Less than 4 words
        const words = newText.split(/\s+/);
        if (words.length >= 4) {
            setOpen(false);
            return;
        }

        // Check 2: Does not contain highlighted word (brackets)
        if (newText.includes('[') || newText.includes(']')) {
            setOpen(false);
            return;
        }

        // Check 3: Check if selection is inside a Badge
        const parentElement = anchorNode.parentElement;
        if (parentElement.closest('.bg-pii')) {
            setOpen(false);
            return;
        }

        // Identify Part Index
        const partIndex = parseInt(parentElement.getAttribute('data-index'), 10);
        if (isNaN(partIndex)) {
            setOpen(false);
            return;
        }

        const rect = newRange.getBoundingClientRect();
        setPosition({
            x: rect.left,
            y: rect.bottom
        });
        setSelectionData({
            partIndex,
            start,
            end,
            text: newText
        });
        setOpen(true);
    };

    const handleAnonymize = () => {
        if (!selectionData) return;
        const { partIndex, start, end, text } = selectionData;

        // Split by brackets to reconstruct parts array as seen in render
        const parts = localMessage.split(/(\[[^\]]+\])/g);

        if (parts[partIndex] === undefined) return;

        const originalPart = parts[partIndex];
        const newPart = originalPart.substring(0, start) + `[ANONYME_${text}]` + originalPart.substring(end);

        parts[partIndex] = newPart;
        const newMessage = parts.join('');

        setLocalMessage(newMessage);
        setOpen(false);
        // Clear selection
        window.getSelection().removeAllRanges();
    };

    // Split by brackets, keeping the brackets in the split result for now
    // Regex: split by [content]
    const parts = localMessage.split(/(\[[^\]]+\])/g);

    return (
        <div className='flex flex-row-reverse w-full'>
            <div onMouseUp={handleMouseUp} className="relative bg-accent rounded-3xl px-5 py-2.5 user-message flex-grow-0">


                <DropdownMenu open={open} onOpenChange={setOpen}>
                    <DropdownMenuTrigger asChild>
                        <div
                            style={{
                                position: 'fixed',
                                top: position.y,
                                left: position.x,
                                width: '1px',
                                height: '1px',
                                visibility: 'hidden',
                                pointerEvents: 'none'
                            }}
                        />
                    </DropdownMenuTrigger>
                    <DropdownMenuContent align="start">
                        <DropdownMenuGroup>
                            <DropdownMenuItem onSelect={handleAnonymize}>
                                Anonymiser
                            </DropdownMenuItem>
                        </DropdownMenuGroup>
                    </DropdownMenuContent>
                </DropdownMenu>
            </div>
        </div>
    );
}

export default function UserMessage() {
    const [show, setShow] = useState(true);
    return (
        <div className="flex flex-col gap-2">
            {props.author == 'user' ? (
                <div className='flex flex-row-reverse w-full'>
                    {/* <div className="relative bg-accent rounded-3xl px-5 py-2.5 user-message flex-grow-0"> */}
                    <Markdown dic={props.dic} show={show}>{props.message}</Markdown>
                    {/* </div> */}
                </div>
            ) : (
                <Markdown dic={props.dic} show={show}>{props.message}</Markdown>
            )}
            <div className="flex justify-end">
                <Button variant="outline" size="icon" onClick={() => setShow(!show)}>
                    {show ? <Eye /> : <EyeClosed />}
                </Button>
            </div>
        </div>
    );
}

