import React, { useMemo, useState } from 'react';
import { Accordion, Badge, Button, Col, Form, InputGroup, Row } from 'react-bootstrap';
import type { UserRole } from '../../../../types/auth';
import { PermissionOptionCard } from './PermissionOptionCard';
import type { PermissionSection, PermissionStatus } from './permissionTypes';

interface Option {
    value: number;
    label: string;
}

export interface UserAccessFormData {
    role: UserRole;
    is_active: boolean;
    contact_id: number | '';
    comercializadora_id: number | '';
    permissions: string[];
    revoked_permissions: string[];
}

interface Props {
    data: UserAccessFormData;
    setData: (field: keyof UserAccessFormData, value: UserAccessFormData[keyof UserAccessFormData]) => void;
    errors: Partial<Record<string, string>>;
    permissionHierarchy: PermissionSection[];
    roleDefaults: Record<UserRole, string[]>;
    assignableRoles: UserRole[];
    contactOptions: Option[];
    comercializadoraOptions: Option[];
}

const ROLE_LABELS: Record<UserRole, string> = {
    super_admin: 'Super administrador',
    admin: 'Administrador',
    user: 'Estándar',
    colaborador: 'Colaborador',
    prescriptor: 'Prescriptor',
    comercializadora: 'Comercializadora',
};

export const UserAccessFields = ({
    data,
    setData,
    errors,
    permissionHierarchy,
    roleDefaults,
    assignableRoles,
    contactOptions,
    comercializadoraOptions,
}: Props) => {
    const [permissionSearch, setPermissionSearch] = useState('');
    const [statusFilter, setStatusFilter] = useState<'all' | PermissionStatus>('all');
    const inherited = useMemo(
        () => new Set(roleDefaults[data.role] ?? []),
        [data.role, roleDefaults],
    );
    const additional = useMemo(() => new Set(data.permissions), [data.permissions]);
    const revoked = useMemo(() => new Set(data.revoked_permissions), [data.revoked_permissions]);

    const isSelected = (permission: string) => (
        (inherited.has(permission) && !revoked.has(permission)) || additional.has(permission)
    );

    const statusOf = (permission: string): PermissionStatus => {
        if (inherited.has(permission)) {
            return revoked.has(permission) ? 'revoked' : 'inherited';
        }

        return additional.has(permission) ? 'additional' : 'available';
    };

    const visibleHierarchy = useMemo(() => {
        const query = permissionSearch.trim().toLocaleLowerCase('es');

        return permissionHierarchy
            .map((section) => ({
                ...section,
                options: section.options
                    .map((option) => ({
                        ...option,
                        actions: option.actions.filter((action) => {
                            const matchesText = query === ''
                                || `${section.label} ${option.label} ${option.description} ${option.path} ${action.label} ${action.description}`
                                    .toLocaleLowerCase('es')
                                    .includes(query);
                            const matchesStatus = statusFilter === 'all'
                                || statusOf(action.permission) === statusFilter;

                            return matchesText && matchesStatus;
                        }),
                    }))
                    .filter((option) => option.actions.length > 0),
            }))
            .filter((section) => section.options.length > 0);
    }, [permissionHierarchy, permissionSearch, statusFilter, inherited, additional, revoked]);

    const allPermissions = useMemo(
        () => permissionHierarchy.flatMap((section) => (
            section.options.flatMap((option) => option.actions.map((action) => action.permission))
        )),
        [permissionHierarchy],
    );
    const visiblePermissionSet = useMemo(() => new Set(allPermissions), [allPermissions]);
    const activeCount = allPermissions.filter(isSelected).length;
    const additionalCount = Array.from(additional).filter((permission) => visiblePermissionSet.has(permission)).length;
    const revokedCount = Array.from(revoked).filter((permission) => visiblePermissionSet.has(permission)).length;

    const changeRole = (role: UserRole) => {
        setData('role', role);
        setData('contact_id', '');
        setData('comercializadora_id', '');
        setData('permissions', []);
        setData('revoked_permissions', []);
    };

    const updateSet = (
        field: 'permissions' | 'revoked_permissions',
        source: Set<string>,
        permission: string,
        include: boolean,
    ) => {
        const next = new Set(source);
        include ? next.add(permission) : next.delete(permission);
        setData(field, Array.from(next));
    };

    const togglePermission = (permission: string, checked: boolean, isInherited: boolean) => {
        // Desmarcar un permiso del rol se guarda como revocación; el resto son extras.
        if (isInherited) {
            updateSet('revoked_permissions', revoked, permission, !checked);
            return;
        }

        updateSet('permissions', additional, permission, checked);
    };

    const togglePermissions = (permissions: string[], checked: boolean) => {
        const nextAdditional = new Set(additional);
        const nextRevoked = new Set(revoked);

        permissions.forEach((permission) => {
            if (inherited.has(permission)) {
                checked ? nextRevoked.delete(permission) : nextRevoked.add(permission);
            } else {
                checked ? nextAdditional.add(permission) : nextAdditional.delete(permission);
            }
        });

        setData('permissions', Array.from(nextAdditional));
        setData('revoked_permissions', Array.from(nextRevoked));
    };

    return (
        <>
            <Row>
                <Col md={6} className="mb-3">
                    <Form.Group>
                        <Form.Label>Rol <span className="text-danger">*</span></Form.Label>
                        <Form.Select
                            id="user-role-select"
                            value={data.role}
                            onChange={(event) => changeRole(event.target.value as UserRole)}
                            isInvalid={Boolean(errors.role)}
                        >
                            {assignableRoles.map((role) => (
                                <option key={role} value={role}>{ROLE_LABELS[role]}</option>
                            ))}
                        </Form.Select>
                        <Form.Control.Feedback type="invalid">{errors.role}</Form.Control.Feedback>
                    </Form.Group>
                </Col>

                <Col md={6} className="mb-3 d-flex align-items-center">
                    <Form.Check
                        type="switch"
                        id="user-is-active"
                        label="Usuario activo"
                        checked={data.is_active}
                        onChange={(event) => setData('is_active', event.target.checked)}
                    />
                </Col>

                {['colaborador', 'prescriptor'].includes(data.role) && (
                    <Col md={6} className="mb-3">
                        <Form.Group>
                            <Form.Label>Contacto asociado <span className="text-danger">*</span></Form.Label>
                            <Form.Select
                                id="user-contact-select"
                                value={data.contact_id}
                                onChange={(event) => setData('contact_id', Number(event.target.value) || '')}
                                isInvalid={Boolean(errors.contact_id)}
                            >
                                <option value="">Selecciona un contacto</option>
                                {contactOptions.map((option) => (
                                    <option key={option.value} value={option.value}>{option.label}</option>
                                ))}
                            </Form.Select>
                            <Form.Control.Feedback type="invalid">{errors.contact_id}</Form.Control.Feedback>
                        </Form.Group>
                    </Col>
                )}

                {data.role === 'comercializadora' && (
                    <Col md={6} className="mb-3">
                        <Form.Group>
                            <Form.Label>Comercializadora asociada <span className="text-danger">*</span></Form.Label>
                            <Form.Select
                                id="user-comercializadora-select"
                                value={data.comercializadora_id}
                                onChange={(event) => setData('comercializadora_id', Number(event.target.value) || '')}
                                isInvalid={Boolean(errors.comercializadora_id)}
                            >
                                <option value="">Selecciona una comercializadora</option>
                                {comercializadoraOptions.map((option) => (
                                    <option key={option.value} value={option.value}>{option.label}</option>
                                ))}
                            </Form.Select>
                            <Form.Control.Feedback type="invalid">{errors.comercializadora_id}</Form.Control.Feedback>
                        </Form.Group>
                    </Col>
                )}
            </Row>

            <Form.Group className="mt-2" id="user-permission-editor">
                <div className="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
                    <div>
                        <Form.Label className="mb-0 fs-5">Accesos y permisos</Form.Label>
                        <small className="text-muted d-block">
                            Selecciona qué opciones del menú verá el usuario y qué podrá hacer dentro de cada una.
                        </small>
                    </div>
                    <Badge bg="primary" pill>{activeCount} de {allPermissions.length} activos</Badge>
                </div>
                {data.role === 'super_admin' && (
                    <div className="alert alert-warning py-2" id="super-admin-permissions-notice">
                        <small>El super administrador tiene acceso total por definición, así que estos ajustes no le afectan.</small>
                    </div>
                )}
                <Row className="g-2 mb-3">
                    <Col lg={8}>
                        <InputGroup>
                            <InputGroup.Text aria-hidden="true">⌕</InputGroup.Text>
                            <Form.Control
                                id="permission-search"
                                value={permissionSearch}
                                onChange={(event) => setPermissionSearch(event.target.value)}
                                placeholder="Buscar una pantalla, acción o descripción…"
                                aria-label="Buscar permisos"
                            />
                            {permissionSearch && (
                                <Button
                                    id="permission-search-clear"
                                    variant="outline-secondary"
                                    onClick={() => setPermissionSearch('')}
                                >
                                    Limpiar
                                </Button>
                            )}
                        </InputGroup>
                    </Col>
                    <Col lg={4}>
                        <Form.Select
                            id="permission-status-filter"
                            value={statusFilter}
                            onChange={(event) => setStatusFilter(event.target.value as 'all' | PermissionStatus)}
                            aria-label="Filtrar permisos por estado"
                        >
                            <option value="all">Todos los estados</option>
                            <option value="inherited">Heredados del rol</option>
                            <option value="additional">Adicionales</option>
                            <option value="revoked">Revocados</option>
                            <option value="available">No asignados</option>
                        </Form.Select>
                    </Col>
                </Row>

                <div className="d-flex flex-wrap gap-2 mb-3 small">
                    <Badge bg="light" text="dark">Heredado: incluido por el rol</Badge>
                    <Badge bg="info">Adicional: añadido a este usuario</Badge>
                    <Badge bg="danger">Revocado: retirado solo a este usuario</Badge>
                </div>

                {visibleHierarchy.length === 0 ? (
                    <div className="alert alert-light border text-center" id="permission-empty-state">
                        No hay permisos que coincidan con la búsqueda o el filtro seleccionado.
                    </div>
                ) : (
                    <Accordion alwaysOpen defaultActiveKey={visibleHierarchy.map((section) => section.id)}>
                        {visibleHierarchy.map((section) => {
                            const sectionPermissions = section.options.flatMap((option) => (
                                option.actions.map((action) => action.permission)
                            ));
                            const sectionSelected = sectionPermissions.filter(isSelected).length;
                            const sectionAllSelected = sectionSelected === sectionPermissions.length;
                            const sectionPartiallySelected = sectionSelected > 0 && !sectionAllSelected;

                            return (
                                <Accordion.Item eventKey={section.id} key={section.id}>
                                    <Accordion.Header>
                                        <span className="me-2">{section.label}</span>
                                        <Badge bg="light" text="dark">
                                            {sectionSelected}/{sectionPermissions.length}
                                        </Badge>
                                    </Accordion.Header>
                                    <Accordion.Body>
                                        <div className="d-flex flex-wrap justify-content-between gap-2 mb-3">
                                            <div className="d-flex align-items-start gap-2">
                                                <input
                                                    id={`permission-section-${section.id}`}
                                                    className="form-check-input mt-1"
                                                    type="checkbox"
                                                    checked={sectionAllSelected}
                                                    ref={(element) => {
                                                        if (element) element.indeterminate = sectionPartiallySelected;
                                                    }}
                                                    onChange={(event) => togglePermissions(sectionPermissions, event.target.checked)}
                                                    aria-label={`Asignar todos los permisos de ${section.label}`}
                                                />
                                                <small className="text-muted">{section.description}</small>
                                            </div>
                                            <div className="btn-group btn-group-sm" role="group" aria-label={`Acciones de ${section.label}`}>
                                                <Button
                                                    id={`permission-section-${section.id}-select`}
                                                    size="sm"
                                                    variant="outline-primary"
                                                    onClick={() => togglePermissions(sectionPermissions, true)}
                                                >
                                                    Seleccionar todo
                                                </Button>
                                                <Button
                                                    id={`permission-section-${section.id}-clear`}
                                                    size="sm"
                                                    variant="outline-danger"
                                                    onClick={() => togglePermissions(sectionPermissions, false)}
                                                >
                                                    Quitar todo
                                                </Button>
                                            </div>
                                        </div>
                                        <Row className="g-3">
                                            {section.options.map((option) => (
                                                <Col lg={6} key={option.id}>
                                                    <PermissionOptionCard
                                                        option={option}
                                                        isSelected={isSelected}
                                                        statusOf={statusOf}
                                                        onToggleAction={(permission, checked) => (
                                                            togglePermission(permission, checked, inherited.has(permission))
                                                        )}
                                                        onToggleOption={togglePermissions}
                                                    />
                                                </Col>
                                            ))}
                                        </Row>
                                    </Accordion.Body>
                                </Accordion.Item>
                            );
                        })}
                    </Accordion>
                )}

                {(additionalCount > 0 || revokedCount > 0) && (
                    <div className="alert alert-info mt-3 mb-0" id="permission-change-summary">
                        <strong>Personalización respecto al rol:</strong>{' '}
                        {additionalCount} permiso(s) adicional(es) y {revokedCount} revocación(es).
                    </div>
                )}
            </Form.Group>
        </>
    );
};
