import React, { useState, useMemo, useEffect } from 'react';
import { MapContainer, TileLayer, Polygon, useMapEvents, Marker, Popup } from 'react-leaflet';
import { X, Home, DollarSign, User, Info, Edit2, Save, Check, MapPin, Loader2, Plus, AlertCircle, ShieldCheck } from 'lucide-react';
import 'leaflet/dist/leaflet.css';
import { useMockStore } from '../data/mockStore';
import { useAuth } from '../context/AuthContext';
import { SpotlightCard } from '../components/SpotlightCard';
import { useTheme } from '../context/ThemeContext';
import PropertyDetailDrawer from '../components/maps/PropertyDetailDrawer';

// --- ICONS ---
import { logger } from '../utils/logger';
import { toast }
    from 'sonner';
import Loader from '../components/Loader';

// Fix for default Leaflet marker icons not showing up
import L from 'leaflet';
import icon from 'leaflet/dist/images/marker-icon.png';
import iconShadow from 'leaflet/dist/images/marker-shadow.png';

let DefaultIcon = L.icon({
    iconUrl: icon,
    shadowUrl: iconShadow,
    iconSize: [25, 41],
    iconAnchor: [12, 41]
});

L.Marker.prototype.options.icon = DefaultIcon;

// --- COMPONENTS ---

const StatusBadge = ({ status }) => {
    const colors = {
        "Neutral": "bg-violet-400",
        "Hot Lead": "bg-red-500",
        "Renovated": "bg-blue-500",
        "Customer": "bg-emerald-500",
        "Not Interested": "bg-white border border-zinc-200 text-zinc-900 shadow-sm"
    };
    return (
        <span className={`px-2 py-1 rounded text-[10px] uppercase font-bold text-white shadow-sm ${colors[status] || "bg-zinc-400"}`}>
            {status}
        </span>
    );
};

// Map Interaction Component
const MapInteraction = ({ onMapClick }) => {
    useMapEvents({
        click(e) {
            onMapClick(e.latlng);
        },
    });
    return null;
};

const MapLegend = () => {
    const [isOpen, setIsOpen] = useState(false);

    return (
        <>
            {/* Mobile Toggle - Top Right */}
            <button
                onClick={() => setIsOpen(!isOpen)}
                className="md:hidden absolute bottom-5 left-6 z-[2000] bg-white dark:bg-zinc-900 p-3 rounded-full shadow-xl border border-zinc-200 dark:border-white/10 text-zinc-600 dark:text-zinc-400"
            >
                <Info size={20} />
            </button>

            {/* Legend Content - Above Toggle on Mobile */}
            <div className={`absolute bottom-[4.5rem] left-6 md:bottom-6 md:right-auto md:top-auto md:left-6 z-[2000] bg-white/95 dark:bg-black/95 backdrop-blur-md p-4 rounded-2xl border border-zinc-200 dark:border-white/10 shadow-xl transition-all duration-300 origin-bottom-left
                ${isOpen ? 'scale-100 opacity-100' : 'scale-0 opacity-0 md:scale-100 md:opacity-100'}
            `}>
                <h4 className="text-[10px] font-black uppercase tracking-widest text-zinc-500 mb-3 flex items-center justify-between">
                    Map Legend
                    <button onClick={() => setIsOpen(false)} className="md:hidden ml-4"><X size={14} /></button>
                </h4>
                <div className="space-y-2">
                    <div className="flex items-center space-x-2">
                        <div className="w-3 h-3 rounded-full bg-red-500 shadow-sm shadow-red-500/50"></div>
                        <span className="text-xs font-bold text-zinc-700 dark:text-zinc-300">Hot Lead</span>
                    </div>
                    <div className="flex items-center space-x-2">
                        <div className="w-3 h-3 rounded-full bg-emerald-500 shadow-sm shadow-emerald-500/50"></div>
                        <span className="text-xs font-bold text-zinc-700 dark:text-zinc-300">Customer</span>
                    </div>
                    <div className="flex items-center space-x-2">
                        <div className="w-3 h-3 rounded-full bg-blue-500 shadow-sm shadow-blue-500/50"></div>
                        <span className="text-xs font-bold text-zinc-700 dark:text-zinc-300">Renovated</span>
                    </div>
                    <div className="flex items-center space-x-2">
                        <div className="w-3 h-3 rounded-full bg-violet-400 shadow-sm shadow-violet-400/50"></div>
                        <span className="text-xs font-bold text-zinc-700 dark:text-zinc-300">Neutral</span>
                    </div>
                    <div className="flex items-center space-x-2">
                        <div className="w-3 h-3 rounded-full bg-white border-2 border-zinc-300 dark:border-zinc-500 shadow-sm"></div>
                        <span className="text-xs font-bold text-zinc-700 dark:text-zinc-300">Not Interested</span>
                    </div>
                </div>
            </div>
        </>
    );
};

// Map Resizer Component
const MapResizer = () => {
    const map = useMapEvents({});

    useEffect(() => {
        const resizeObserver = new ResizeObserver(() => {
            map.invalidateSize();
        });
        const container = map.getContainer();
        resizeObserver.observe(container);

        return () => {
            resizeObserver.disconnect();
        };
    }, [map]);

    return null;
};

// Map View
const MapView = ({ data, onSelect, onMapCreate }) => {
    const mapStart = [33.0708, -96.7455];
    const { theme } = useTheme(); // Get current theme

    return (
        <MapContainer center={mapStart} zoom={18} scrollWheelZoom={true} className="w-full h-full z-0 relative outline-none" style={{ height: "100%", width: "100%" }}>

            <MapResizer />

            {/* 
                - Light Mode: Standard vibrant OSM tiles (no filters)
                - Dark Mode: Inverted, Grayscale, High Contrast for dark map
                - Key prop forces remount on theme change to ensure tiles update immediately
            */}
            <TileLayer
                key={theme}
                attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                className={theme === 'dark'
                    ? 'map-tiles filter invert grayscale contrast-100'
                    : 'map-tiles'
                }
            />

            <MapInteraction onMapClick={onMapCreate} />

            {data.map((item) => {
                let color = "#a78bfa"; // Violet-400 (New Neutral)
                let fillOpacity = 0.2;

                switch (item.canvassingStatus) {
                    case "Hot Lead":
                        color = "#ef4444"; // Red-500
                        fillOpacity = 0.4;
                        break;
                    case "Customer":
                        color = "#10b981"; // Emerald-500
                        fillOpacity = 0.3;
                        break;
                    case "Renovated":
                        color = "#3b82f6"; // Blue-500
                        break;
                    case "Not Interested":
                        color = "#ffffff"; // Bright White
                        fillOpacity = 0.4; // Higher opacity for white visibility
                        break;
                    default:
                        // Neutral (Violet)
                        break;
                }

                return (
                    <Polygon
                        key={item.id}
                        positions={item.polygon}
                        pathOptions={{
                            color: color,
                            fillColor: color,
                            fillOpacity: fillOpacity,
                            weight: 2
                        }}
                        eventHandlers={{
                            click: (e) => {
                                L.DomEvent.stopPropagation(e); // Prevent map click
                                onSelect(item);
                            },
                        }}
                    />
                );
            })}
        </MapContainer>
    );
};

// --- MAIN PAGE COMPONENT --- //

function Maps() {
    const { properties, setProperties, updatePropertyStatus } = useMockStore();
    const { user } = useAuth();
    const [isLoading, setIsLoading] = useState(true);

    useEffect(() => {
        // Simulate initial map load
        const timer = setTimeout(() => setIsLoading(false), 1000);
        return () => clearTimeout(timer);
    }, []);

    // Selection State
    const [selectedPropertyId, setSelectedPropertyId] = useState(null);
    const [newPropertyLocation, setNewPropertyLocation] = useState(null); // { lat, lng, address }
    const [loadingAddr, setLoadingAddr] = useState(false);

    // Derived Selection
    const selectedProperty = useMemo(() =>
        properties.find(p => p.id === selectedPropertyId),
        [properties, selectedPropertyId]
    );

    // -- Handlers --

    // 1. Click Existing Polygon
    const handlePropertySelect = (property) => {
        setNewPropertyLocation(null); // Clear new creation mode
        setSelectedPropertyId(property.id);
    };

    // 2. Click Empty Map (Create New)
    const handleMapCreate = async (latlng) => {
        // Only Field Agents (employees) can create
        if (user?.role !== 'FIELD_AGENT' && user?.role !== 'ADMIN') return;

        setSelectedPropertyId(null);
        setNewPropertyLocation({ lat: latlng.lat, lng: latlng.lng, address: '' });
        setLoadingAddr(true);

        try {
            // Reverse Geocode using simple OSM Nominatim API
            // Note: In production, user should cache/throttle or use paid service.
            const response = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${latlng.lat}&lon=${latlng.lng}`);

            if (!response.ok) throw new Error("Geocoding service unavailable");

            const data = await response.json();

            setNewPropertyLocation(prev => ({
                ...prev,
                address: data.display_name || "Unknown Location"
            }));
            logger.info("Geocoding successful", { lat: latlng.lat, lng: latlng.lng });
        } catch (err) {
            logger.error("Geocoding failed", err);
            toast.error("Could not fetch address", { description: "Using coordinates instead." });
            setNewPropertyLocation(prev => ({ ...prev, address: "Location Found (Address Unavailable)" }));
        } finally {
            setLoadingAddr(false);
        }
    };

    // 3. Save Changes (Create or Update)
    const handleSave = (formData) => {
        try {
            // Construct the full data objects based on schema
            const newOwnerData = {
                fullName: formData.ownerName,
                primaryPhoneNumber: formData.ownerPhone || "Pending",
                emailAddress: formData.ownerEmail || "Pending",
                details: {
                    occupation: formData.occupation,
                    ownershipType: formData.ownershipType,
                    willingToSell: formData.willingToSell,
                    desiredPrice: formData.desiredPrice,
                    minPrice: formData.minPrice,
                    ownerAddress: formData.ownerAddress
                }
            };

            const newPropertyData = {
                propertyType: formData.propertyType,
                currentEstimatedMarketValue: parseInt(formData.marketValue) || 0,
                notes: formData.notes,
                details: {
                    builtUpArea: formData.builtUpArea,
                    lotSize: formData.lotSize,
                    yearBuilt: formData.yearBuilt,
                    bedrooms: formData.bedrooms,
                    bathrooms: formData.bathrooms,
                    parkingSpaces: formData.parkingSpaces,
                    taxValue: formData.taxValue,
                    roofCondition: formData.roofCondition,
                    lastRenovationDate: formData.lastRenovationDate,

                    // Rental Status (Enhanced)
                    isRented: formData.isRented === 'Yes',
                    currentlyRented: formData.isRented === 'Yes', // Sync both just in case
                    currentTenantName: formData.tenantName,
                    tenantPhone: formData.tenantPhone,
                    tenantEmail: formData.tenantEmail,
                    tenantOccupation: formData.tenantOccupation,
                    tenantEmployer: formData.tenantEmployer,
                    tenantAnnualIncome: formData.tenantIncome,
                    livingStatus: formData.livingStatus,
                    leaseType: formData.leaseType,
                    leaseSignedDate: formData.leaseSigned,
                    leaseStartDate: formData.leaseStart,
                    leaseEndDate: formData.leaseEnd,
                    currentMonthlyRentAmount: formData.currentRent,

                    ownerWillingToRent: formData.ownerWillingToRent === 'Yes',
                    expectedMonthlyRentAmount: formData.expectedRent,

                    // Location (can be expanded)
                    schoolDistrict: formData.schoolDistrict,
                    neighborhoodRating: formData.neighborhoodRating
                }
            };

            const newInsuranceData = {
                insurance_company: formData.insurance_company,
                insurance_company_not_listed: formData.insurance_company_not_listed,
                damage_location: formData.damage_location,
                date_of_loss: formData.date_of_loss,
                claim_filed: formData.claim_filed === 'Yes',
                claim_number: formData.claim_number,
                has_paperwork: formData.has_paperwork === 'Yes',
                adjuster_name: formData.adjuster_name,
                adjuster_phone: formData.adjuster_phone,
                adjuster_ext: formData.adjuster_ext,
                adjuster_type: formData.adjuster_type,
                adjuster_fax: formData.adjuster_fax,
                adjuster_email: formData.adjuster_email,
                met_with_adjuster: formData.met_with_adjuster === 'Yes',
                claim_approved: formData.claim_approved === 'Yes',
            };

            if (selectedPropertyId) {
                // Update Existing
                setProperties(prev => prev.map(p => {
                    if (p.id === selectedPropertyId) {
                        return {
                            ...p,
                            canvassingStatus: formData.status,
                            ownerData: { ...p.ownerData, ...newOwnerData },
                            propertyData: { ...p.propertyData, ...newPropertyData.details, ...newPropertyData }, // Merge Flattened and Nested
                            insuranceData: { ...p.insuranceData, ...newInsuranceData }
                        };
                    }
                    return p;
                }));
                toast.success("Property updated successfully");
            } else if (newPropertyLocation) {
                // Create New
                const newId = properties.length + 1;
                // Generate Polygon (Simple Box around center) as placeholder
                // In real app, user would draw. Here we just spawn a box.
                const d = 0.0001;
                const newPoly = [
                    [newPropertyLocation.lat + d, newPropertyLocation.lng - d],
                    [newPropertyLocation.lat + d, newPropertyLocation.lng + d],
                    [newPropertyLocation.lat - d, newPropertyLocation.lng + d],
                    [newPropertyLocation.lat - d, newPropertyLocation.lng - d],
                ];

                const newItem = {
                    id: newId,
                    center: [newPropertyLocation.lat, newPropertyLocation.lng],
                    polygon: newPoly,
                    canvassingStatus: formData.status,
                    ownerData: {
                        ownerId: `OWN-NEW-${newId}`,
                        ...newOwnerData
                    },
                    propertyData: {
                        propertyId: `P-NEW-${newId}`,
                        propertyAddress: newPropertyLocation.address,
                        ...newPropertyData.details,
                        ...newPropertyData
                    },
                    insuranceData: {
                        ...newInsuranceData
                    }
                };
                setProperties(prev => [...prev, newItem]);
                toast.success("New property added to map");
                setSelectedPropertyId(newId); // Select it
                setNewPropertyLocation(null); // Exit create mode
            }
        } catch (err) {
            logger.error("Failed to save property", err);
            toast.error("Failed to save changes", { description: "Please check your input." });
        }
    };

    if (isLoading) return <Loader fullScreen text="Loading Territory Map..." />;

    return (
        <div className="w-full h-full relative bg-zinc-50 dark:bg-black overflow-hidden transition-colors duration-300" style={{ height: "calc(100vh - 0px)" }}>
            <MapView
                data={properties}
                onSelect={handlePropertySelect}
                onMapCreate={handleMapCreate}
            />
            <MapLegend />

            <PropertyDetailDrawer
                isOpen={!!selectedProperty || !!newPropertyLocation}
                onClose={() => { setSelectedPropertyId(null); setNewPropertyLocation(null); }}
                data={selectedProperty}
                newLocation={newPropertyLocation}
                loadingAddr={loadingAddr}
                onSave={handleSave}
            />
            <span className="attribution-ghost">igotsar.matyas | LynkedUpPro - Turns out roofing CRMs don't build themselves. Who knew?</span>
        </div>
    );
}

export default Maps;
