import { Form, Head } from '@inertiajs/react';
import {
    Lock,
    ShieldCheck,
    ShieldHalf,
    UserCog,
    Users,
} from 'lucide-react';
import type { ReactNode } from 'react';
import RoleController from '@/actions/App/Http/Controllers/RoleController';
import { FormField } from '@/components/crm/native-select';
import {
    Callout,
    PageHeader,
    SectionCard,
} from '@/components/crm/page-header';
import { RuleFlag, StatusPill } from '@/components/crm/status-badge';
import { StatStrip } from '@/components/crm/kpi-tile';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { cn } from '@/lib/utils';
import { index as rolesIndex } from '@/routes/roles';
import type { RoleSummary } from '@/types';

type Props = {
    roles: RoleSummary[];
    permissionGroups: Record<string, Record<string, string>>;
    can: {
        manage: boolean;
    };
};

export default function RolesIndex({ roles, permissionGroups, can }: Props) {
    const totalPermissions = Object.values(permissionGroups).reduce(
        (total, group) => total + Object.keys(group).length,
        0,
    );

    const staffAssigned = roles.reduce(
        (total, role) => total + role.users_count,
        0,
    );

    const protectedRoles = roles.filter((role) => role.is_protected).length;

    return (
        <>
            <Head title="Roles and permissions" />

            <PageHeader
                eyebrow={
                    <>
                        <span>
                            {roles.length} roles · {totalPermissions} permissions
                            in the catalogue
                        </span>
                    </>
                }
                title="Roles and permissions"
                description="A role is a bundle of permissions. Give every staff member the role that matches their job, and nothing more."
            />

            <StatStrip
                items={[
                    {
                        label: 'Roles',
                        value: roles.length,
                        tone: 'info',
                        icon: ShieldHalf,
                    },
                    {
                        label: 'Permissions',
                        value: totalPermissions,
                        tone: 'slate',
                        icon: Lock,
                    },
                    {
                        label: 'Staff assigned',
                        value: staffAssigned,
                        tone: 'solar',
                        icon: Users,
                    },
                    {
                        label: 'Protected roles',
                        value: protectedRoles,
                        tone: 'warning',
                        icon: ShieldCheck,
                    },
                ]}
            />

            <div className="grid gap-4">
                {roles.map((role) => (
                    <RolePanel
                        key={role.name}
                        role={role}
                        permissionGroups={permissionGroups}
                        totalPermissions={totalPermissions}
                        canManage={can.manage}
                    />
                ))}
            </div>

            {can.manage ? (
                <Form {...RoleController.store.form()}>
                    {({ processing, errors }) => (
                        <SectionCard
                            title="Create a role"
                            description="Use this for a role this business needs that is not already listed above, for example a Regional Coordinator or a Scheduling Officer."
                            icon={UserCog}
                            tone="solar"
                        >
                            <FormField
                                label="Role name"
                                htmlFor="name"
                                error={errors.name}
                                required
                            >
                                <Input
                                    id="name"
                                    name="name"
                                    required
                                    placeholder="Regional Coordinator"
                                    className="max-w-sm"
                                />
                            </FormField>

                            <div className="mt-4">
                                <PermissionGroups
                                    permissionGroups={permissionGroups}
                                    selected={[]}
                                    idPrefix="new-role"
                                />
                            </div>

                            <Button disabled={processing} className="mt-4">
                                Create role
                            </Button>
                        </SectionCard>
                    )}
                </Form>
            ) : null}
        </>
    );
}

/**
 * One role and its permission matrix. A role that can be edited is wrapped in
 * its own form so each role saves independently.
 */
function RolePanel({
    role,
    permissionGroups,
    totalPermissions,
    canManage,
}: {
    role: RoleSummary;
    permissionGroups: Record<string, Record<string, string>>;
    totalPermissions: number;
    canManage: boolean;
}) {
    const editable = canManage && !role.is_protected;
    const coverage =
        totalPermissions === 0
            ? 0
            : Math.round((role.permissions.length / totalPermissions) * 100);

    const coverageTone =
        role.permissions.length === totalPermissions
            ? 'success'
            : role.permissions.length === 0
              ? 'slate'
              : 'info';

    const actions = (
        <div className="flex flex-wrap items-center gap-1.5">
            <StatusPill tone={coverageTone} className="text-[11px]">
                {role.permissions.length} of {totalPermissions} · {coverage}%
            </StatusPill>
            <StatusPill tone="slate" className="text-[11px]">
                <Users className="size-3" />
                {role.users_count} staff
            </StatusPill>
            {role.is_protected ? (
                <RuleFlag tone="warning">Protected</RuleFlag>
            ) : null}
            {!role.is_system ? <RuleFlag tone="solar">Custom</RuleFlag> : null}
        </div>
    );

    const body = (
        processing: boolean,
        errors: Record<string, string | undefined>,
    ): ReactNode => (
        <>
            {role.is_protected ? (
                <Callout
                    tone="info"
                    icon={ShieldCheck}
                    title="The Super Admin role cannot be edited or deleted"
                    className="mb-4"
                >
                    It always holds every permission, so nobody can lock the owner
                    out of the system. Create a separate role for anything that
                    needs narrower access.
                </Callout>
            ) : null}

            {!role.is_protected && role.users_count > 0 ? (
                <p className="text-muted-foreground mb-4 flex items-center gap-2 text-xs">
                    <Users className="size-3.5 shrink-0" />
                    Assigned to {role.users_count} staff, so move them to another
                    role before removing this one.
                </p>
            ) : null}

            <PermissionGroups
                permissionGroups={permissionGroups}
                selected={role.permissions}
                editable={editable}
                idPrefix={role.name}
            />

            {errors.permissions ? (
                <p className="text-destructive mt-2 text-sm">
                    {errors.permissions}
                </p>
            ) : null}

            {editable ? (
                <div className="mt-4 flex items-center gap-2">
                    <Button disabled={processing} size="sm">
                        Save permissions
                    </Button>
                    <span className="text-muted-foreground text-xs">
                        Changes apply the next time this role's staff load a page.
                    </span>
                </div>
            ) : null}
        </>
    );

    if (!editable) {
        return (
            <SectionCard
                title={role.name}
                description={role.description}
                icon={role.is_protected ? ShieldCheck : ShieldHalf}
                tone={role.is_protected ? 'warning' : 'info'}
                actions={actions}
            >
                {body(false, {})}
            </SectionCard>
        );
    }

    return (
        <Form {...RoleController.update.form({ role: role.name })} className="contents">
            {({ processing, errors }) => (
                <SectionCard
                    title={role.name}
                    description={role.description}
                    icon={ShieldHalf}
                    tone="info"
                    actions={actions}
                >
                    {body(processing, errors)}
                </SectionCard>
            )}
        </Form>
    );
}

/**
 * The permission checkboxes, grouped exactly as the backend catalogue groups
 * them. Names are submitted as permissions[].
 */
function PermissionGroups({
    permissionGroups,
    selected,
    editable = true,
    idPrefix,
}: {
    permissionGroups: Record<string, Record<string, string>>;
    selected: string[];
    editable?: boolean;
    idPrefix: string;
}) {
    return (
        <div className="grid gap-3 lg:grid-cols-2">
            {Object.entries(permissionGroups).map(([group, permissions]) => {
                const entries = Object.entries(permissions);
                const selectedCount = entries.filter(([permission]) =>
                    selected.includes(permission),
                ).length;

                const groupTone =
                    selectedCount === entries.length
                        ? 'success'
                        : selectedCount === 0
                          ? 'slate'
                          : 'info';

                return (
                    <div
                        key={group}
                        className="bg-surface/50 ring-hairline rounded-lg px-3 py-2.5 ring-1 ring-inset"
                    >
                        <div className="mb-2 flex items-center justify-between gap-2">
                            <p className="crm-label">{group}</p>
                            <span
                                className={cn(
                                    'crm-num text-[11px] font-medium',
                                    groupTone === 'success'
                                        ? 'text-success'
                                        : groupTone === 'info'
                                          ? 'text-info'
                                          : 'text-muted-foreground',
                                )}
                            >
                                {selectedCount}/{entries.length}
                            </span>
                        </div>

                        <div className="grid gap-0.5">
                            {entries.map(([permission, description]) => {
                                const id = `${idPrefix}-${permission}`;

                                return (
                                    <label
                                        key={permission}
                                        htmlFor={id}
                                        className={cn(
                                            'flex items-start gap-2.5 rounded-md px-1.5 py-1 text-sm',
                                            editable
                                                ? 'hover:bg-accent/50 cursor-pointer'
                                                : 'cursor-default',
                                        )}
                                    >
                                        <input
                                            id={id}
                                            type="checkbox"
                                            name="permissions[]"
                                            value={permission}
                                            defaultChecked={selected.includes(
                                                permission,
                                            )}
                                            disabled={!editable}
                                            className="border-input mt-0.5 size-4 shrink-0 rounded-[4px] border shadow-xs disabled:opacity-60"
                                        />
                                        <span className="min-w-0">
                                            <span className="block text-[13px] leading-tight">
                                                {description}
                                            </span>
                                            <span className="text-muted-foreground block font-mono text-[11px]">
                                                {permission}
                                            </span>
                                        </span>
                                    </label>
                                );
                            })}
                        </div>
                    </div>
                );
            })}
        </div>
    );
}

RolesIndex.layout = {
    breadcrumbs: [
        {
            title: 'Staff',
            href: '',
        },
        {
            title: 'Roles and permissions',
            href: rolesIndex(),
        },
    ],
};
