import React, { useState, useMemo } from 'react';
import { Script } from "@/interfaces/exam";
import Message from './Message';
import AutoExpandingTextArea from '@/components/Low/AutoExpandingTextarea';
import { Card, CardContent } from '@/components/ui/card';
import Input from '@/components/Low/Input';
import { FaFemale, FaMale, FaPlus } from 'react-icons/fa';
import clsx from 'clsx';

export interface Speaker {
    id: number;
    name: string;
    gender: 'male' | 'female';
    color: string;
    position: 'left' | 'right';
}

type Gender = 'male' | 'female';

export interface ScriptLine {
    name: string;
    gender: Gender;
    text: string;
    voice?: string;
}

interface MessageWithPosition extends ScriptLine {
    position: 'left' | 'right';
}

interface Props {
    section: number;
    editing?: boolean;
    local?: Script;
    setLocal: (script: Script) => void;
}

const colorOptions = [
    'red', 'blue', 'green', 'purple', 'pink', 'indigo', 'teal', 'orange',
    'cyan', 'emerald', 'sky', 'violet', 'fuchsia', 'rose', 'lime', 'slate'
];

const ScriptEditor: React.FC<Props> = ({ section, editing = false, local, setLocal }) => {
    const isConversation = [1, 3].includes(section);
    const speakerCount = section === 1 ? 2 : 4;

    if (local === undefined) {
        if (isConversation) {
            setLocal([]);
        } else {
            setLocal('');
        }
    }

    const [selectedSpeaker, setSelectedSpeaker] = useState<string>('');
    const [newMessage, setNewMessage] = useState('');

    const [speakers, setSpeakers] = useState<Speaker[]>(() => {
        if (local === undefined) {
            return Array.from({ length: speakerCount }, (_, index) => ({
                id: index,
                name: '',
                gender: 'male',
                color: colorOptions[index],
                position: index % 2 === 0 ? 'left' : 'right'
            }));
        }
        
        const existingScript = local as ScriptLine[];
        const existingSpeakers = new Set<string>();
        const speakerGenders = new Map<string, 'male' | 'female'>();

        if (Array.isArray(existingScript)) {
            existingScript.forEach(line => {
                existingSpeakers.add(line.name);
                speakerGenders.set(line.name, line.gender.toLowerCase() === 'female' ? 'female' : 'male' as 'male' | 'female');
            });
        }

        const speakerArray = Array.from(existingSpeakers);
        const totalNeeded = Math.max(speakerCount, speakerArray.length);

        return Array.from({ length: totalNeeded }, (_, index) => {
            if (index < speakerArray.length) {
                return {
                    id: index,
                    name: speakerArray[index],
                    gender: speakerGenders.get(speakerArray[index]) || 'male',
                    color: colorOptions[index],
                    position: index % 2 === 0 ? 'left' : 'right'
                };
            }
            return {
                id: index,
                name: '',
                gender: 'male',
                color: colorOptions[index],
                position: index % 2 === 0 ? 'left' : 'right'
            };
        });
    });

    const speakerProperties = useMemo(() => {
        return speakers.reduce((acc, speaker) => {
            if (speaker.name) {
                acc[speaker.name] = {
                    color: speaker.color,
                    gender: speaker.gender
                };
            }
            return acc;
        }, {} as Record<string, { color: string; gender: 'male' | 'female' }>);
    }, [speakers]);

    const allSpeakersConfigured = useMemo(() => {
        return speakers.every(speaker => speaker.name.trim() !== '');
    }, [speakers]);

    const updateSpeaker = (index: number, updates: Partial<Speaker>) => {
        const updatedSpeakers = speakers.map((speaker, i) => {
            if (i === index) {
                return { ...speaker, ...updates };
            }
            return speaker;
        });
        setSpeakers(updatedSpeakers);

        if (Array.isArray(local)) {
            if ('name' in updates && speakers[index].name) {
                const oldName = speakers[index].name;
                const newName = updates.name || '';
                const updatedScript = local.map(line => {
                    if (line.name === oldName) {
                        return { ...line, name: newName };
                    }
                    return line;
                });
                setLocal(updatedScript);
            }

            if ('gender' in updates && speakers[index].name && updates.gender) {
                const name = speakers[index].name;
                const newGender = updates.gender;
                const updatedScript = local.map(line => {
                    if (line.name === name) {
                        return { ...line, gender: newGender };
                    }
                    return line;
                });
                setLocal(updatedScript);
            }
        }

        if ('name' in updates && speakers[index].name === selectedSpeaker) {
            setSelectedSpeaker(updates.name || '');
        }
    };


    const addMessage = () => {
        if (!isConversation || !selectedSpeaker || !newMessage.trim()) return;
        if (!Array.isArray(local)) return;

        const speaker = speakers.find(s => s.name === selectedSpeaker);
        if (!speaker) return;

        const newLine: ScriptLine = {
            name: selectedSpeaker,
            gender: speaker.gender,
            text: newMessage.trim()
        };

        const updatedScript = [...local, newLine];
        setLocal(updatedScript);
        setNewMessage('');
    };

    const updateMessage = (index: number, newText: string) => {
        if (!Array.isArray(local)) return;

        const updatedScript = [...local];
        updatedScript[index] = { ...updatedScript[index], text: newText };
        setLocal(updatedScript);
    };

    const deleteMessage = (index: number) => {
        if (!Array.isArray(local)) return;

        const updatedScript = local.filter((_, i) => i !== index);
        setLocal(updatedScript);
    };

    const updateMonologue = (text: string) => {
        setLocal(text);
    };

    const messages = useMemo(() => {
        if (typeof local === 'string' || !Array.isArray(local)) return [];

        return local.reduce<MessageWithPosition[]>((acc, line, index) => {
            const normalizedLine = {
                ...line,
                gender: line.gender.toLowerCase() === 'female' ? 'female' : 'male'
            } as ScriptLine;

            if (index === 0) {
                acc.push({ ...normalizedLine, position: 'left' });
            } else {
                const prevMsg = acc[index - 1];
                const position = line.name === prevMsg.name
                    ? prevMsg.position
                    : (prevMsg.position === 'left' ? 'right' : 'left');
                acc.push({ ...normalizedLine, position });
            }
            return acc;
        }, []);
    }, [local]);

    if (!isConversation) {
        return (
            <Card>
                <CardContent className="py-10">
                    <div className="w-full">
                        {editing ? (
                            <AutoExpandingTextArea
                                value={local as string}
                                onChange={updateMonologue}
                                placeholder='Write the monologue here...'
                            />
                        ) : (
                            <div className="p-8 shadow-inner border border-gray-200 bg-gray-50 rounded-xl">
                                <span>{(local as string) || "Edit, generate or import your own audio."}</span>
                            </div>
                        )}
                    </div>
                </CardContent>
            </Card>
        );
    }

    return (
        <Card>
            <CardContent className="py-10">
                <div className="space-y-6">
                    {editing && (
                        <div className="bg-white rounded-2xl p-6 shadow-inner border mb-8">
                            <h3 className="text-lg font-medium text-gray-700 mb-6">Edit Conversation</h3>
                            <div className="space-y-4 mb-6">
                                {speakers.map((speaker, index) => (
                                    <div key={index} className="flex items-center gap-4">
                                        <div className="flex-1">
                                            <Input
                                                type="text"
                                                name=""
                                                value={speaker.name}
                                                onChange={(text) => updateSpeaker(index, { name: text })}
                                                placeholder="Speaker name"
                                            />
                                        </div>

                                        <div className="w-[140px] relative">
                                            <select
                                                value={speaker.gender}
                                                onChange={(e) => updateSpeaker(index, { gender: e.target.value as 'male' | 'female' })}
                                                className="w-full appearance-none px-4 py-2 border border-gray-200 rounded-full text-base bg-white focus:ring-1 focus:ring-blue-500 focus:outline-none"
                                            >
                                                <option value="female">Female</option>
                                                <option value="male">Male</option>
                                            </select>
                                            <div className="absolute right-3 top-2.5 pointer-events-none">
                                                {speaker.gender === 'male' ? (
                                                    <FaMale className="w-5 h-5 text-blue-500" />
                                                ) : (
                                                    <FaFemale className="w-5 h-5 text-pink-500" />
                                                )}
                                            </div>
                                        </div>
                                    </div>
                                ))}
                            </div>
                            <div className="flex gap-4">
                                <div className="w-[240px] flex flex-col gap-2">
                                    <select
                                        value={selectedSpeaker}
                                        onChange={(e) => setSelectedSpeaker(e.target.value)}
                                        disabled={!allSpeakersConfigured}
                                        className="w-full h-[42px] px-4 appearance-none border border-gray-200 rounded-full focus:ring-1 focus:ring-blue-500 focus:outline-none bg-white text-gray-700 text-base disabled:bg-gray-100"
                                    >
                                        <option value="">Select Speaker ...</option>
                                        {speakers.filter(s => s.name).map((speaker) => (
                                            <option key={speaker.id} value={speaker.name}>
                                                {speaker.name}
                                            </option>
                                        ))}
                                    </select>
                                    <button
                                        onClick={addMessage}
                                        disabled={!selectedSpeaker || !newMessage.trim() || !allSpeakersConfigured}
                                        className={clsx(
                                            "w-full h-[42px] rounded-lg flex items-center justify-center gap-2 transition-colors font-medium",
                                            !selectedSpeaker || !newMessage.trim() || !allSpeakersConfigured
                                                ? 'bg-gray-100 text-gray-500 cursor-not-allowed'
                                                : 'bg-blue-500 text-white hover:bg-blue-600'
                                        )}
                                    >
                                        <FaPlus className="w-4 h-4" />
                                        Add
                                    </button>
                                </div>

                                <div className="flex-1">
                                    <AutoExpandingTextArea
                                        value={newMessage}
                                        onChange={setNewMessage}
                                        placeholder={allSpeakersConfigured ? "Type your message..." : "Configure all speakers first"}
                                        disabled={!allSpeakersConfigured}
                                        className="w-full min-h-[96px] px-4 py-2 border border-gray-200 rounded-lg focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-base resize-none disabled:bg-gray-100"
                                    />
                                </div>
                            </div>
                        </div>
                    )}

                    <div className="space-y-4">
                        {messages.map((message, index) => {
                            const properties = speakerProperties[message.name];
                            if (!properties) return null;

                            return (
                                <Message
                                    key={index}
                                    message={message}
                                    color={properties.color}
                                    editing={editing}
                                    onEdit={(text: string) => updateMessage(index, text)}
                                    onDelete={() => deleteMessage(index)}
                                />
                            );
                        })}
                    </div>
                </div>
            </CardContent>
        </Card>
    );
};

export default ScriptEditor;
