import React, { useMemo, useState } from 'react';
import { Database, Lock, Search } from 'lucide-react';
import type { SObjectDescribe, ObjectPermission } from '../../types';
import { controlledByParentAuthoring, type ControlledByParentAuthoring } from '../../infrastructure/api/users';

interface ObjectPermissionsTableProps {
    permissions: ObjectPermission[];
    schemas: SObjectDescribe[];
    onToggle: (objectApiName: string, field: keyof ObjectPermission) => void;
    onToggleAll?: (objectApiNames: string[], field: keyof ObjectPermission, value: boolean) => void;
}

export const ObjectPermissionsTable: React.FC<ObjectPermissionsTableProps> = ({
    permissions,
    schemas,
    onToggle,
    onToggleAll,
}) => {
    const [searchQuery, setSearchQuery] = useState('');

    // Metadata-driven ControlledByParent detection. A row is "controlled by
    // parent" iff its object schema is a ControlledByParent child (sharingModel
    // alone — matching the backend's RejectParentControlledChildWrite, which
    // rejects EVERY such child, well-formed or malformed). These children have no
    // authorable ObjectPermissions row — the backend owns their effective access
    // — so the editor shows a non-editable controlled-by-parent cell instead of
    // guessed CRUD checkboxes. Keying off the sharing-parent edge alone would be
    // stricter than the backend and render malformed children editable.
    const controlledByObject = useMemo(() => {
        const map = new Map<string, ControlledByParentAuthoring>();
        for (const schema of schemas) {
            const cbp = controlledByParentAuthoring(schema);
            if (cbp) map.set(schema.name.toLowerCase(), cbp);
        }
        return map;
    }, [schemas]);

    const controlledOf = (objectName: string | undefined): ControlledByParentAuthoring | undefined =>
        objectName ? controlledByObject.get(objectName.toLowerCase()) : undefined;

    // #4: Filter permissions by search query
    const filteredPermissions = useMemo(() => {
        if (!searchQuery.trim()) return permissions;
        const q = searchQuery.toLowerCase();
        return permissions.filter(p => {
            const objectName = p.SobjectType || '';
            const schema = schemas.find(s => s.name === objectName);
            const label = schema?.label || objectName;
            return objectName.toLowerCase().includes(q) || label.toLowerCase().includes(q);
        });
    }, [permissions, schemas, searchQuery]);

    // Calculate column-level state against the visible search result set only.
    const columnStates = useMemo(() => {
        const editablePermissions = filteredPermissions.filter(p => !controlledOf(p.SobjectType));
        const total = editablePermissions.length;
        if (total === 0) return { read: false, create: false, edit: false, delete: false, viewAll: false, modifyAll: false };

        const checkedCounts = editablePermissions.reduce((acc, p) => ({
            read: acc.read + (p.PermissionsRead ? 1 : 0),
            create: acc.create + (p.PermissionsCreate ? 1 : 0),
            edit: acc.edit + (p.PermissionsEdit ? 1 : 0),
            delete: acc.delete + (p.PermissionsDelete ? 1 : 0),
            viewAll: acc.viewAll + (p.PermissionsViewAllRecords ? 1 : 0),
            modifyAll: acc.modifyAll + (p.PermissionsModifyAllRecords ? 1 : 0),
        }), { read: 0, create: 0, edit: 0, delete: 0, viewAll: 0, modifyAll: 0 });

        return {
            read: checkedCounts.read === total,
            create: checkedCounts.create === total,
            edit: checkedCounts.edit === total,
            delete: checkedCounts.delete === total,
            viewAll: checkedCounts.viewAll === total,
            modifyAll: checkedCounts.modifyAll === total,
            readPartial: checkedCounts.read > 0 && checkedCounts.read < total,
            createPartial: checkedCounts.create > 0 && checkedCounts.create < total,
            editPartial: checkedCounts.edit > 0 && checkedCounts.edit < total,
            deletePartial: checkedCounts.delete > 0 && checkedCounts.delete < total,
            viewAllPartial: checkedCounts.viewAll > 0 && checkedCounts.viewAll < total,
            modifyAllPartial: checkedCounts.modifyAll > 0 && checkedCounts.modifyAll < total,
        };
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [filteredPermissions, controlledByObject]);

    const handleHeaderToggle = (field: keyof ObjectPermission, currentlyAllChecked: boolean) => {
        const visibleObjectApiNames = filteredPermissions
            .filter(p => !controlledOf(p.SobjectType))
            .map(p => p.SobjectType)
            .filter((objectApiName): objectApiName is string => Boolean(objectApiName));

        if (onToggleAll) {
            onToggleAll(visibleObjectApiNames, field, !currentlyAllChecked);
        } else {
            filteredPermissions.forEach(p => {
                if (controlledOf(p.SobjectType)) {
                    return;
                }
                if (p[field] === currentlyAllChecked) {
                    onToggle(p.SobjectType || '', field);
                }
            });
        }
    };

    // Helper for header checkbox styling (indeterminate state)
    const HeaderCheckbox: React.FC<{
        checked: boolean;
        partial?: boolean;
        onChange: () => void;
        colorClass?: string;
        title: string;
    }> = ({ checked, partial, onChange, colorClass = 'text-blue-600', title }) => (
        <div className="flex flex-col items-center gap-1">
            <input
                type="checkbox"
                checked={checked}
                ref={(el) => {
                    if (el) el.indeterminate = !!partial && !checked;
                }}
                onChange={onChange}
                className={`rounded border-slate-300 ${colorClass} focus:ring-offset-0 cursor-pointer`}
                title={`Toggle all: ${title}`}
            />
            <span className="text-xs text-slate-500 whitespace-nowrap">{title}</span>
        </div>
    );

    if (permissions.length === 0) {
        return (
            <div className="p-8 text-center text-slate-500">
                <Database size={48} className="mx-auto mb-4 opacity-50" />
                <p>No object permissions configured</p>
            </div>
        );
    }

    return (
        <div className="overflow-x-auto">
            {/* #4: Object search */}
            <div className="mb-3 relative">
                <Search size={16} className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400" />
                <input
                    type="text"
                    value={searchQuery}
                    onChange={e => setSearchQuery(e.target.value)}
                    placeholder="Search objects..."
                    className="w-full pl-9 pr-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white"
                />
                {searchQuery && (
                    <span className="absolute right-3 top-1/2 -translate-y-1/2 text-xs text-slate-400">
                        {filteredPermissions.length} / {permissions.length}
                    </span>
                )}
            </div>
            <table className="w-full text-sm">
                <thead className="bg-slate-50 border-b border-slate-200">
                    <tr>
                        <th className="px-4 py-3 text-left font-semibold text-slate-700">Object</th>
                        <th className="px-4 py-3 text-center w-20">
                            <HeaderCheckbox
                                checked={columnStates.read}
                                partial={columnStates.readPartial}
                                onChange={() => handleHeaderToggle('PermissionsRead', columnStates.read)}
                                title="Read"
                            />
                        </th>
                        <th className="px-4 py-3 text-center w-20">
                            <HeaderCheckbox
                                checked={columnStates.create}
                                partial={columnStates.createPartial}
                                onChange={() => handleHeaderToggle('PermissionsCreate', columnStates.create)}
                                title="Create"
                            />
                        </th>
                        <th className="px-4 py-3 text-center w-20">
                            <HeaderCheckbox
                                checked={columnStates.edit}
                                partial={columnStates.editPartial}
                                onChange={() => handleHeaderToggle('PermissionsEdit', columnStates.edit)}
                                title="Edit"
                            />
                        </th>
                        <th className="px-4 py-3 text-center w-20">
                            <HeaderCheckbox
                                checked={columnStates.delete}
                                partial={columnStates.deletePartial}
                                onChange={() => handleHeaderToggle('PermissionsDelete', columnStates.delete)}
                                title="Delete"
                            />
                        </th>
                        <th className="px-4 py-3 text-center w-24 border-l border-slate-200">
                            <HeaderCheckbox
                                checked={columnStates.viewAll}
                                partial={columnStates.viewAllPartial}
                                onChange={() => handleHeaderToggle('PermissionsViewAllRecords', columnStates.viewAll)}
                                colorClass="text-purple-600"
                                title="View All"
                            />
                        </th>
                        <th className="px-4 py-3 text-center w-24">
                            <HeaderCheckbox
                                checked={columnStates.modifyAll}
                                partial={columnStates.modifyAllPartial}
                                onChange={() => handleHeaderToggle('PermissionsModifyAllRecords', columnStates.modifyAll)}
                                colorClass="text-purple-600"
                                title="Modify All"
                            />
                        </th>
                    </tr>
                </thead>
                <tbody className="divide-y divide-slate-100">
                    {filteredPermissions.map(perm => {
                        const objectName = perm.SobjectType || '';
                        const schema = schemas.find(s => s.name === objectName);
                        const label = schema?.label || objectName;
                        const controlled = controlledOf(objectName);

                        const objectCell = (
                            <td className="px-4 py-3 font-medium text-slate-900 flex items-center gap-2">
                                <Database size={16} className="text-slate-400" />
                                {label}
                                <span className="text-xs text-slate-400 font-normal font-mono ml-1">({objectName})</span>
                            </td>
                        );

                        // ControlledByParent children have no authorable row: the
                        // backend rejects persisting one (resolved parent or not)
                        // and owns their effective access. State that, instead of
                        // guessed CRUD checkboxes.
                        //
                        // The unresolved case deliberately does not diagnose the
                        // metadata: a child can be parent-controlled without a
                        // direct sharing-parent relationship (two-step shapes), so
                        // "not configured" would be an accusation this surface
                        // cannot support. Say what is true either way — permissions
                        // come from the parent record and are not editable here.
                        if (controlled) {
                            return (
                                <tr key={objectName} className="hover:bg-slate-50">
                                    {objectCell}
                                    <td colSpan={6} className="px-4 py-3 text-sm text-slate-700">
                                        <span className="inline-flex items-center gap-1.5">
                                            <Lock size={14} className="text-slate-500" />
                                            {controlled.parentObject ? (
                                                <span>
                                                    Controlled by{' '}
                                                    <span className="font-semibold text-slate-900">
                                                        {controlled.parentObject}
                                                    </span>
                                                </span>
                                            ) : (
                                                <span>Controlled by its parent record</span>
                                            )}
                                        </span>
                                    </td>
                                </tr>
                            );
                        }

                        return (
                            <tr key={objectName} className="hover:bg-slate-50">
                                {objectCell}
                                <td className="px-4 py-3 text-center">
                                    <input type="checkbox" checked={!!perm.PermissionsRead} onChange={() => onToggle(objectName, 'PermissionsRead')}
                                        className="rounded border-slate-300 text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed" />
                                </td>
                                <td className="px-4 py-3 text-center">
                                    <input type="checkbox" checked={!!perm.PermissionsCreate} onChange={() => onToggle(objectName, 'PermissionsCreate')}
                                        className="rounded border-slate-300 text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed" />
                                </td>
                                <td className="px-4 py-3 text-center">
                                    <input type="checkbox" checked={!!perm.PermissionsEdit} onChange={() => onToggle(objectName, 'PermissionsEdit')}
                                        className="rounded border-slate-300 text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed" />
                                </td>
                                <td className="px-4 py-3 text-center">
                                    <input type="checkbox" checked={!!perm.PermissionsDelete} onChange={() => onToggle(objectName, 'PermissionsDelete')}
                                        className="rounded border-slate-300 text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed" />
                                </td>
                                <td className="px-4 py-3 text-center border-l border-slate-200">
                                    <input type="checkbox" checked={!!perm.PermissionsViewAllRecords} onChange={() => onToggle(objectName, 'PermissionsViewAllRecords')}
                                        className="rounded border-slate-300 text-purple-600 focus:ring-purple-500 disabled:opacity-50 disabled:cursor-not-allowed" />
                                </td>
                                <td className="px-4 py-3 text-center">
                                    <input type="checkbox" checked={!!perm.PermissionsModifyAllRecords} onChange={() => onToggle(objectName, 'PermissionsModifyAllRecords')}
                                        className="rounded border-slate-300 text-purple-600 focus:ring-purple-500 disabled:opacity-50 disabled:cursor-not-allowed" />
                                </td>
                            </tr>
                        );
                    })}
                </tbody>
            </table>
        </div >
    );
};
