import Form from '@/components/form/Form';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { yupResolver } from '@hookform/resolvers/yup';
import { usePage } from '@inertiajs/react';
import { Plus } from 'lucide-react';
import { useMemo } from 'react';
import { useFormContext } from 'react-hook-form';
import * as yup from 'yup';
import { Switch } from '../ui/switch';

// ── App name → tenant_access app slug (null = always visible) ──
// Platform and Report are always shown regardless of active package.
const APP_SLUG_MAP: Record<string, string | null> = {
    User:         'user',
    Contact:      'contact',
    Sales:        'sales',
    Purchase:     'purchase',
    Inventory:    'inventory',
    Product:      'product',
    Promotion:    'promotion',
    Ecommerce:    'ecommerce',
    Productivity: 'productivity',
    Academic:     'academic',
    Website:      'website',
    Platform:     null,
};

// ── Group name → tenant_access module slug (null = show when app is active) ──
const MODULE_SLUG_MAP: Record<string, string | null> = {
    Employee:         'user_employees',
    Partner:          'user_partners',
    Teacher:          'user_teachers',
    BoardMember:      'user_board_members',
    Customer:         'contact_customers',
    Supplier:         'contact_suppliers',
    Order:            'sales_orders',
    Cart:             'sales_carts',
    Payment:          'sales_payments',
    Delivery:         'sales_deliveries',
    SalesReturn:      'sales_return',
    CreditNote:       'credit_notes',
    Purchase:         'purchase_purchase',
    PurchaseReturn:   'purchase_return',
    Inventory:        'inventory_list',
    StockAdjust:      'inventory_stock_adjust',
    StockHistory:     'inventory_stock_history',
    StockTransfer:    'inventory_stock_transfer',
    Product:          'product_product',
    ProductBrand:     'product_brand',
    ProductCategory:  'product_category',
    ProductVariant:   'product_variant',
    Task:             'productivity_task',
    Note:             'productivity_note',
    Reminder:         'productivity_reminder',
    Event:            'productivity_event',
    EcommercePage:    'ecommerce_pages',
    EcommerceBlog:    'ecommerce_blog',
    PromotionBanner:  'ecommerce_promotion_banner',
    AcademicYear:     'academic_year',
    AcademicSection:  'academic_section',
    Subject:          'academic_subject',
    InstituteClass:   'academic_class',
    Curriculum:       'academic_curriculum',
    Routine:          'academic_routine',
    Syllabus:         'academic_syllabus',
    Result:           'academic_result',
    AdmissionForm:    'academic_admission_form',
    Program:          'academic_program',
    AcademicCalendar: 'academic_calendar',
    WebsitePage:      'website_page',
    WebsiteBlog:      'website_blog',
    WebsiteMenu:      'website_menu',
    Gallery:          'website_gallery',
    Notice:           'website_notice',
    Testimonial:      'website_testimonial',
    Achievement:      'website_achievement',
    CustomerQuery:    'website_customer_query',
    // Promotion sub-groups: no module gate — show if Promotion app is active
    Offer:     null,
    Coupon:    null,
    FlashSale: null,
    Discount:  null,
    // Platform and Report groups: always visible (scope managed by NO_SCOPE_APPS)
    Role:           null,
    Administration: null,
    AppSettings:    null,
    AppDashboard:   null,
};

type ScopeType = 'global' | 'local' | 'branch' | 'country';

interface AccessLevel {
    value: number;
    label: string;
    scopeString: ScopeType;
}

const roleSchema = yup.object({
    name: yup.string().required('Role name is required').trim(),
    permissions: yup.array().min(1, 'Please select at least one permission').required('Please select at least one permission'),
});

interface RoleFormWithHookFormProps {
    modulePermissions: any;
    initialData?: any;
    onSubmit: (data: any) => void;
    submitButtonText: string;
    isEdit?: boolean;
    isView?: boolean;
}

const SCOPES = [
    { label: 'Global', value: 'global' },
    { label: 'Branch', value: 'branch' },
    { label: 'Self', value: 'local' },
];

// Apps whose groups never get a scope — access is managed by code, not role scope
const NO_SCOPE_APPS = new Set(['Platform', 'Report']);

function RoleFormFields({ modulePermissions, isEdit = false, isView = false }: { modulePermissions: any; isEdit?: boolean; isView?: boolean }) {
    const { watch, setValue, formState: { errors } } = useFormContext();
    const formData = watch();

    const { roleTypes = [], accessLevels = [] } = usePage<{
        roleTypes?: { value: number; label: string; color: string; badgeClass: string }[];
        accessLevels?: AccessLevel[];
    }>().props;

    const { tenant_access } = usePage<{
        tenant_access?: { apps: string[]; modules: string[] };
    }>().props;

    const allApps = useMemo(() => {
        const raw = modulePermissions || {};
        const activeApps    = tenant_access?.apps    ?? [];
        const activeModules = tenant_access?.modules ?? [];

        return Object.fromEntries(
            Object.entries(raw)
                .filter(([appName]) => {
                    if (appName === 'Report' || appName === 'Platform') return true;
                    const appSlug = APP_SLUG_MAP[appName];
                    if (appSlug === undefined || appSlug === null) return true;
                    return activeApps.includes(appSlug);
                })
                .map(([appName, groups]) => {
                    const filteredGroups = Object.fromEntries(
                        Object.entries(groups as Record<string, any>).filter(([groupName]) => {
                            if (appName === 'Report' || appName === 'Platform') return true;
                            if (!(groupName in MODULE_SLUG_MAP)) return true;
                            const moduleSlug = MODULE_SLUG_MAP[groupName];
                            if (!moduleSlug) return true;
                            return activeModules.includes(moduleSlug);
                        }),
                    );
                    return [appName, filteredGroups];
                })
                .filter(([, groups]) => Object.keys(groups as any).length > 0),
        );
    }, [modulePermissions, tenant_access]);

    const moduleCategories = Object.keys(allApps).reduce(
        (acc, appName) => { acc[appName] = Object.keys(allApps[appName]); return acc; },
        {} as Record<string, string[]>,
    );

    const getGroupPermissions = (appName: string, groupName: string) => allApps[appName]?.[groupName] || {};

    const generateSlug = (name: string) =>
        name.toLowerCase().trim()
            .replace(/[^a-z0-9\s-]/g, '')
            .replace(/\s+/g, '-')
            .replace(/-+/g, '-')
            .replace(/^-|-$/g, '');

    const roleSlug = useMemo(() => isEdit ? formData.slug : generateSlug(formData.name || ''), [formData.name, formData.slug, isEdit]);

    const getScopeString = (level: number): ScopeType =>
        accessLevels.find((al) => al.value === level)?.scopeString ?? accessLevels[0]?.scopeString ?? 'global';

    const primaryScopeString = () => getScopeString(Number(formData.primary_access_level ?? 1));

    const togglePermission = (slug: string, checked: boolean) => {
        const currentPermissions = formData.permissions || [];
        const newPermissions = checked ? [...currentPermissions, slug] : currentPermissions.filter((p: string) => p !== slug);
        setValue('permissions', newPermissions);

        const findAppAndGroup = () => {
            for (const appName of Object.keys(allApps)) {
                for (const groupName of Object.keys(allApps[appName])) {
                    if (Object.values(allApps[appName][groupName]).includes(slug)) return { appName, groupName };
                }
            }
            return null;
        };

        const location = findAppAndGroup();
        if (location && !NO_SCOPE_APPS.has(location.appName)) {
            const { groupName } = location;
            const currentScopes = formData.moduleScopes || {};
            if (checked) {
                if (!currentScopes[groupName]) {
                    setValue('moduleScopes', { ...currentScopes, [groupName]: { scope: primaryScopeString(), is_show: 1 } });
                }
            } else {
                const groupPerms = Object.values(getGroupPermissions(location.appName, groupName)) as string[];
                const hasOther = groupPerms.some((s) => s !== slug && newPermissions.includes(s));
                if (!hasOther) {
                    const { [groupName]: _, ...rest } = currentScopes;
                    setValue('moduleScopes', rest);
                }
            }
        }
    };

    const toggleGroup = (appName: string, groupName: string, checked: boolean) => {
        const groupPerms = Object.values(getGroupPermissions(appName, groupName));
        const current = formData.permissions || [];
        const next = checked
            ? Array.from(new Set([...current, ...groupPerms]))
            : current.filter((p: string) => !groupPerms.includes(p));
        setValue('permissions', next);

        if (!NO_SCOPE_APPS.has(appName)) {
            const currentScopes = formData.moduleScopes || {};
            if (checked) {
                if (!currentScopes[groupName]) {
                    setValue('moduleScopes', { ...currentScopes, [groupName]: { scope: primaryScopeString(), is_show: 1 } });
                }
            } else {
                const { [groupName]: _, ...rest } = currentScopes;
                setValue('moduleScopes', rest);
            }
        }
    };

    const setGroupScope = (groupName: string, scope: ScopeType) => {
        const currentScopes = formData.moduleScopes || {};
        const existing = currentScopes[groupName] || { scope: 'global', is_show: 1 };
        setValue('moduleScopes', { ...currentScopes, [groupName]: { ...existing, scope } });
    };

    const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const value = e.target.value;
        setValue('name', value);
        if (!isEdit) setValue('slug', generateSlug(value));
    };

    const handleAccessLevelChange = (newValue: string) => {
        const level = Number(newValue);
        setValue('primary_access_level', level);
        const scopeStr = getScopeString(level);
        const currentScopes = formData.moduleScopes || {};
        const updated: Record<string, { scope: ScopeType; is_show: number }> = {};
        Object.entries(currentScopes).forEach(([mod, val]: [string, any]) => {
            updated[mod] = { scope: scopeStr, is_show: val?.is_show ?? 1 };
        });
        setValue('moduleScopes', updated);
    };

    const isGroupSelected = (appName: string, groupName: string) => {
        const slugs = Object.values(getGroupPermissions(appName, groupName)) as string[];
        return slugs.length > 0 && slugs.every((s) => (formData.permissions || []).includes(s));
    };

    return (
        <div className="space-y-3">
            {/* ── Role Information ── */}
            <Card className="border shadow-none">
                <CardHeader className="px-4 pt-3 pb-2">
                    <CardTitle className="text-sm font-semibold uppercase tracking-wide text-gray-500">Role Information</CardTitle>
                </CardHeader>
                <CardContent className="px-4 pb-3">
                    <div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
                        {/* Role Name */}
                        <div>
                            <Label htmlFor="role-name" className="mb-1 block text-xs font-medium text-gray-600">
                                Role Name *
                            </Label>
                            <Input
                                id="role-name"
                                name="name"
                                placeholder="e.g. Sales Manager"
                                value={formData.name || ''}
                                onChange={handleNameChange}
                                disabled={isView}
                                className={`h-8 text-sm ${errors.name ? 'border-red-500' : ''}`}
                            />
                            {errors.name && <p className="mt-1 text-xs text-red-600">{(errors.name as any)?.message}</p>}
                        </div>

                        {/* Slug */}
                        <div>
                            <Label htmlFor="role-slug" className="mb-1 block text-xs font-medium text-gray-600">
                                Slug
                            </Label>
                            <Input
                                id="role-slug"
                                value={roleSlug}
                                disabled
                                className="h-8 bg-gray-50 text-sm text-gray-500"
                            />
                        </div>

                        {/* Role Type */}
                        {roleTypes.length > 0 && (
                            <div>
                                <Label htmlFor="role-type" className="mb-1 block text-xs font-medium text-gray-600">
                                    Role Type
                                </Label>
                                <Select
                                    disabled={isView}
                                    value={String(formData.type ?? 1)}
                                    onValueChange={(val) => setValue('type', Number(val))}
                                >
                                    <SelectTrigger id="role-type" className="h-8 text-sm">
                                        <SelectValue placeholder="Select type" />
                                    </SelectTrigger>
                                    <SelectContent>
                                        {roleTypes.map((rt) => (
                                            <SelectItem key={rt.value} value={String(rt.value)}>
                                                <span className={`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium ${rt.badgeClass}`}>
                                                    {rt.label}
                                                </span>
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                            </div>
                        )}

                        {/* Access Level */}
                        {accessLevels.length > 0 && (
                            <div>
                                <Label htmlFor="primary-access-level" className="mb-1 block text-xs font-medium text-gray-600">
                                    Access Level
                                </Label>
                                <Select
                                    disabled={isView}
                                    value={String(formData.primary_access_level ?? 1)}
                                    onValueChange={handleAccessLevelChange}
                                >
                                    <SelectTrigger id="primary-access-level" className="h-8 text-sm">
                                        <SelectValue placeholder="Select level" />
                                    </SelectTrigger>
                                    <SelectContent>
                                        {accessLevels.map((al) => (
                                            <SelectItem key={al.value} value={String(al.value)}>
                                                {al.label}
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                            </div>
                        )}

                        {/* Status */}
                        <div>
                            <Label htmlFor="role-status" className="mb-1 block text-xs font-medium text-gray-600">
                                Status
                            </Label>
                            <Select
                                disabled={isView}
                                value={String(formData.status ?? 1)}
                                onValueChange={(val) => setValue('status', Number(val))}
                            >
                                <SelectTrigger id="role-status" className="h-8 text-sm">
                                    <SelectValue placeholder="Select status" />
                                </SelectTrigger>
                                <SelectContent>
                                    <SelectItem value="1">Active</SelectItem>
                                    <SelectItem value="0">Inactive</SelectItem>
                                </SelectContent>
                            </Select>
                        </div>
                    </div>
                </CardContent>
            </Card>

            {/* ── Permissions ── */}
            <div id="permissions" className="space-y-3">
                {errors.permissions && (
                    <p className="text-sm text-red-600">{(errors.permissions as any)?.message}</p>
                )}

                {Object.entries(moduleCategories).map(([appName, groups]) => {
                    const appPermissions = groups.flatMap((g) => Object.values(getGroupPermissions(appName, g))) as string[];
                    const appAllSelected = appPermissions.length > 0 && appPermissions.every((s) => (formData.permissions || []).includes(s));
                    const selectedCount = (formData.permissions || []).filter((p: string) => appPermissions.includes(p)).length;

                    return (
                        <Card key={appName} className="overflow-hidden border shadow-none">
                            {/* App header */}
                            <div className="flex items-center justify-between border-b bg-gray-50 px-4 py-2">
                                <div className="flex items-center gap-2">
                                    <h3 className="text-sm font-semibold capitalize">{appName}</h3>
                                    {selectedCount > 0 && (
                                        <span className="rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-medium text-primary">
                                            {selectedCount} selected
                                        </span>
                                    )}
                                </div>
                                <Button
                                    type="button"
                                    disabled={isView}
                                    variant="ghost"
                                    size="sm"
                                    onClick={(e: React.MouseEvent) => {
                                        e.preventDefault();
                                        const current = formData.permissions || [];
                                        const next = appAllSelected
                                            ? current.filter((p: string) => !appPermissions.includes(p))
                                            : Array.from(new Set([...current, ...appPermissions]));
                                        setValue('permissions', next);

                                        if (!NO_SCOPE_APPS.has(appName)) {
                                            const currentScopes = formData.moduleScopes || {};
                                            if (!appAllSelected) {
                                                const newScopes = { ...currentScopes };
                                                const scopeStr = primaryScopeString();
                                                groups.forEach((g) => { if (!newScopes[g]) newScopes[g] = { scope: scopeStr, is_show: 1 }; });
                                                setValue('moduleScopes', newScopes);
                                            } else {
                                                const newScopes = { ...currentScopes };
                                                groups.forEach((g) => { delete newScopes[g]; });
                                                setValue('moduleScopes', newScopes);
                                            }
                                        }
                                    }}
                                    className={`h-6 px-2 text-xs ${appAllSelected ? 'text-red-600 hover:bg-red-50 hover:text-red-700' : 'text-gray-500 hover:text-gray-700'}`}
                                >
                                    {appAllSelected ? 'Deselect All' : 'Select All'}
                                </Button>
                            </div>

                            {/* Group grid */}
                            <div className="grid grid-cols-1 gap-2 p-3 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4">
                                {groups.map((groupName) => {
                                    const perms = Object.entries(getGroupPermissions(appName, groupName));
                                    const groupSlugs = perms.map(([, s]) => s as string);
                                    const hasPermissions = groupSlugs.some((s) => (formData.permissions || []).includes(s));
                                    const groupSelected = isGroupSelected(appName, groupName);
                                    const scopeValue = (() => {
                                        const v = (formData.moduleScopes || {})[groupName];
                                        return typeof v === 'object' ? v?.scope ?? 'global' : v ?? 'global';
                                    })();

                                    return (
                                        <div key={groupName} className="flex flex-col rounded-lg border bg-white shadow-none">
                                            {/* Group header */}
                                            <div className="flex items-center justify-between gap-2 rounded-t-lg bg-gray-50 px-3 py-2">
                                                <div className="flex items-center gap-2 min-w-0">
                                                    <div className={`size-2 shrink-0 rounded-full ${hasPermissions ? 'bg-primary' : 'bg-gray-300'}`} />
                                                    <span className="truncate text-[13px] font-semibold text-gray-700">{groupName}</span>
                                                </div>
                                                <div className="flex shrink-0 items-center gap-1.5">
                                                    <button
                                                        type="button"
                                                        disabled={isView}
                                                        onClick={() => toggleGroup(appName, groupName, !groupSelected)}
                                                        className="text-xs text-gray-400 hover:text-gray-600 disabled:opacity-40"
                                                    >
                                                        {groupSelected ? 'None' : 'All'}
                                                    </button>
                                                    <Switch
                                                        disabled={isView}
                                                        checked={groupSelected}
                                                        onCheckedChange={(c) => toggleGroup(appName, groupName, c)}
                                                        className="shrink-0 scale-90"
                                                    />
                                                </div>
                                            </div>

                                            {/* Permission rows */}
                                            <div className="flex flex-col px-1.5 py-1.5">
                                                {perms.map(([name, slug]) => {
                                                    const checked = (formData.permissions || []).includes(slug as string);
                                                    return (
                                                        <div
                                                            key={slug as string}
                                                            className={`flex cursor-pointer items-center justify-between rounded px-2.5 py-1.5 transition-colors ${checked ? 'bg-primary/5' : 'hover:bg-gray-50'} ${isView ? 'cursor-not-allowed' : ''}`}
                                                            onClick={() => !isView && togglePermission(slug as string, !checked)}
                                                        >
                                                            <span className={`text-[13px] font-medium leading-none ${checked ? 'text-gray-800' : 'text-gray-500'}`}>
                                                                {name}
                                                            </span>
                                                            <Switch
                                                                disabled={isView}
                                                                checked={checked}
                                                                onCheckedChange={() => {}}
                                                                className="pointer-events-none ml-2 shrink-0 scale-90"
                                                            />
                                                        </div>
                                                    );
                                                })}
                                            </div>

                                            {/* Scope selector — hidden for Platform and Report apps */}
                                            {hasPermissions && !NO_SCOPE_APPS.has(appName) && (
                                                <div className="mt-auto border-t px-3 py-2">
                                                    <RadioGroup
                                                        disabled={isView}
                                                        value={scopeValue}
                                                        onValueChange={(v) => setGroupScope(groupName, v as ScopeType)}
                                                        className="flex items-center gap-3"
                                                    >
                                                        {SCOPES.map((s) => (
                                                            <label
                                                                key={s.value}
                                                                htmlFor={`${groupName}-${s.value}`}
                                                                className={`flex cursor-pointer items-center gap-1.5 ${isView ? 'cursor-not-allowed opacity-50' : ''}`}
                                                            >
                                                                <RadioGroupItem
                                                                    id={`${groupName}-${s.value}`}
                                                                    value={s.value}
                                                                    disabled={isView}
                                                                    className="h-3.5 w-3.5 shrink-0"
                                                                />
                                                                <span className="text-xs text-gray-600">{s.label}</span>
                                                            </label>
                                                        ))}
                                                    </RadioGroup>
                                                </div>
                                            )}
                                        </div>
                                    );
                                })}
                            </div>
                        </Card>
                    );
                })}
            </div>

            {/* Submit */}
            {!isView && (
                <div className="flex gap-3 sm:justify-end">
                    <Button type="button" variant="outline" onClick={() => history.back()} className="sm:w-auto">
                        Cancel
                    </Button>
                    <Button type="submit" className="bg-success text-white hover:bg-brand-800 sm:w-auto">
                        <Plus className="h-4 w-4" />
                        {isEdit ? 'Update Role' : 'Create Role'}
                    </Button>
                </div>
            )}
        </div>
    );
}

export default function RoleForm({
    modulePermissions,
    initialData = {},
    onSubmit,
    submitButtonText,
    isEdit = false,
    isView = false,
}: RoleFormWithHookFormProps) {
    const normalizeModuleScopes = (scopes: any) => {
        if (!scopes) return {};
        const normalized: Record<string, { scope: ScopeType; is_show: number }> = {};
        Object.entries(scopes).forEach(([module, value]: [string, any]) => {
            if (typeof value === 'string') {
                normalized[module] = { scope: value as ScopeType, is_show: 1 };
            } else if (value && typeof value === 'object') {
                normalized[module] = { scope: (value.scope as ScopeType) || 'global', is_show: value.is_show === 0 ? 0 : 1 };
            } else {
                normalized[module] = { scope: 'global', is_show: 1 };
            }
        });
        return normalized;
    };

    const defaultValues = {
        name: '',
        slug: '',
        type: 1,
        primary_access_level: 1,
        status: 1,
        permissions: [],
        ...initialData,
        moduleScopes: normalizeModuleScopes(initialData.moduleScopes || initialData.module_scopes || {}),
    };

    const handleFormSubmit = async (data: any) => {
        const submitData = {
            ...data,
            slug: isEdit
                ? data.slug
                : data.name.toLowerCase().trim()
                    .replace(/[^a-z0-9\s-]/g, '')
                    .replace(/\s+/g, '-')
                    .replace(/-+/g, '-')
                    .replace(/^-|-$/g, ''),
        };
        onSubmit(submitData);
    };

    return (
        <Form defaultValues={defaultValues} resolver={yupResolver(roleSchema)} submitHandler={handleFormSubmit} formClassNames="space-y-3">
            <RoleFormFields modulePermissions={modulePermissions} isEdit={isEdit} isView={isView} />
        </Form>
    );
}
