/**
 * External dependencies.
 */
import { useState, useEffect } from '@wordpress/element';
import SettingsLayout from '../../layout/SettingsLayout';
import { SettingsCard, MultiSelectInput, SelectInput, TextInput, ToggleInput } from '../../templates';
import { fetchOptions, saveOptions } from '../../../api/settings';
import { showPromiseToast } from '../../../utils';

const algorithmOptions = {
    HS256: 'HS256 (shared secret)',
    RS256: 'RS256 (RSA public/private)',
    ES256: 'ES256 (ECDSA)',
};

const roleOptions = Object.entries(window.vajraPluginState?.roles || {}).map(([key, role]) => ({
    key,
    label: role?.name || key,
    description: (role?.description?.replace(/<[^>]+>/g, '') || '').substring(0, 80),
}));

const availableRoleOptions = roleOptions.length ? roleOptions : [
    { key: 'administrator', label: 'Administrator', description: 'Full access' },
    { key: 'editor', label: 'Editor', description: 'Content managers' },
];

const userFieldOptions = [
    { key: 'ID', label: 'User ID' },
    { key: 'user_login', label: 'Username' },
    { key: 'user_email', label: 'Email' },
    { key: 'display_name', label: 'Display Name' },
    { key: 'roles', label: 'Roles' },
];

const endpointRules = [
    { key: 'token', label: 'Token (POST /token)' },
    { key: 'token_refresh', label: 'Token Refresh (POST /token/refresh)' },
    { key: 'token_revoke', label: 'Token Revoke (POST /token/revoke)' },
    { key: 'register', label: 'Register (POST /register)' },
    { key: 'login', label: 'Login (POST /login)' },
    { key: 'forgot_password', label: 'Forgot Password (POST /forgot-password)' },
    { key: 'reset_password', label: 'Reset Password (POST /reset-password)' },
    { key: 'change_password', label: 'Change Password (POST /change-password)' },
];

const accessModes = {
    public: 'Public',
    authenticated: 'Logged-in users',
    roles: 'Specific roles',
};

const GeneralSettings = () => {
    const [options, setOptions] = useState({
        token_expiration: 3600,
        active_algorithm: 'HS256',
        allow_registration_via_api: true,
        auto_login_after_register: true,
        allowed_roles: ['administrator'],
        login_response_fields: ['ID', 'user_login', 'user_email', 'display_name', 'roles'],
        rbac_rules: {},
        rs256_private_key: '',
        rs256_public_key: '',
        es256_private_key: '',
        es256_public_key: '',
        token_meta_fields: [],
        token_acf_fields: [],
        token_woo_fields: [],
    });
    const [expiryFields, setExpiryFields] = useState({ value: 60, unit: 'minutes' });
    const [metaFieldText, setMetaFieldText] = useState('');
    const [acfFieldText, setAcfFieldText] = useState('');
    const [wooFieldText, setWooFieldText] = useState('');

    useEffect(() => {
        const updateOptions = (settings) => {
            const merged = { ...options, ...settings };
            setOptions(merged);
            if (settings.token_expiration) {
                setExpiryFields(convertSecondsToFields(settings.token_expiration));
            }
            if (settings.token_meta_fields) {
                setMetaFieldText(listToMultiline(settings.token_meta_fields));
            }
            if (settings.token_acf_fields) {
                setAcfFieldText(listToMultiline(settings.token_acf_fields));
            }
            if (settings.token_woo_fields) {
                setWooFieldText(listToMultiline(settings.token_woo_fields));
            }
        };
        const res = fetchOptions({ updateOptions });
        showPromiseToast(res, 'Loading settings');
    }, []);

    const updateOption = (value, key) => {
        setOptions({ ...options, [key]: value });
    };

    const updateRbacRule = (key, updates) => {
        setOptions((prev) => {
            const rules = prev.rbac_rules || {};
            return {
                ...prev,
                rbac_rules: {
                    ...rules,
                    [key]: {
                        mode: updates.mode ?? rules[key]?.mode ?? 'public',
                        roles: updates.roles ?? rules[key]?.roles ?? [],
                    },
                },
            };
        });
    };

    const onSave = () => {
        const payload = {
            ...options,
            token_expiration: convertFieldsToSeconds(expiryFields),
            token_meta_fields: parseListInput(metaFieldText),
            token_acf_fields: parseListInput(acfFieldText),
            token_woo_fields: parseListInput(wooFieldText),
        };
        const res = saveOptions({ options: payload });
        showPromiseToast(res, 'Saving', 'Settings updated');
    };

    return (
        <SettingsLayout>
            <SettingsCard
                title="Token Basics"
                description="Define expiration policy and signing algorithm."
                onSave={onSave}
            >
                <div className="grid gap-4 sm:grid-cols-2">
                <TextInput
                        id="token_expiration_value"
                        label="Token Lifetime"
                        type="number"
                        description="Choose how long issued tokens remain valid."
                        value={expiryFields.value}
                        setOption={(val) => setExpiryFields({ ...expiryFields, value: parseInt(val, 10) || 1 })}
                        min={1}
                    />
                    <SelectInput
                        id="token_expiration_unit"
                        label="Unit"
                        value={expiryFields.unit}
                        options={{ minutes: 'Minutes', hours: 'Hours', days: 'Days' }}
                        setOption={(val) => setExpiryFields({ ...expiryFields, unit: val })}
                    />
                </div>
                <SelectInput
                    id="active_algorithm"
                    label="Signing Algorithm"
                    description="Switch between HS256, RS256, or ES256 at any time."
                    value={options.active_algorithm}
                    options={algorithmOptions}
                    setOption={updateOption}
                />
                {options.active_algorithm !== 'HS256' && (
                    <div className="grid gap-4">
                        <label className="text-sm font-semibold text-gray-900">Key Material</label>
                        {options.active_algorithm === 'RS256' && (
                            <>
                                <textarea
                                    className="min-h-[120px] rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500"
                                    value={options.rs256_private_key}
                                    placeholder="RSA PRIVATE KEY"
                                    onChange={(e) => updateOption(e.target.value, 'rs256_private_key')}
                                />
                                <textarea
                                    className="min-h-[120px] rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500"
                                    value={options.rs256_public_key}
                                    placeholder="RSA PUBLIC KEY"
                                    onChange={(e) => updateOption(e.target.value, 'rs256_public_key')}
                                />
                            </>
                        )}
                        {options.active_algorithm === 'ES256' && (
                            <>
                                <textarea
                                    className="min-h-[120px] rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500"
                                    value={options.es256_private_key}
                                    placeholder="EC PRIVATE KEY"
                                    onChange={(e) => updateOption(e.target.value, 'es256_private_key')}
                                />
                                <textarea
                                    className="min-h-[120px] rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500"
                                    value={options.es256_public_key}
                                    placeholder="EC PUBLIC KEY"
                                    onChange={(e) => updateOption(e.target.value, 'es256_public_key')}
                                />
                            </>
                        )}
                    </div>
                )}
            </SettingsCard>

            <SettingsCard
                title="Token Payload"
                description="Select which profile fields and meta data are embedded into JWTs."
                onSave={onSave}
            >
                <MultiSelectInput
                    id="login_response_fields"
                    label="Core User Fields"
                    description="Toggle username, email, roles and more."
                    values={options.login_response_fields || []}
                    options={userFieldOptions}
                    setOption={updateOption}
                />
                <div className="grid gap-4 md:grid-cols-3">
                    <div>
                        <label className="text-sm font-semibold text-gray-900">Profile Meta Keys</label>
                        <p className="text-xs text-gray-500 mb-2">One key per line (e.g. phone, department).</p>
                        <textarea
                            className="min-h-[120px] w-full rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500"
                            value={metaFieldText}
                            onChange={(e) => setMetaFieldText(e.target.value)}
                        />
                    </div>
                    <div>
                        <label className="text-sm font-semibold text-gray-900">ACF Fields</label>
                        <p className="text-xs text-gray-500 mb-2">Provide ACF field names to expose.</p>
                        <textarea
                            className="min-h-[120px] w-full rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500"
                            value={acfFieldText}
                            onChange={(e) => setAcfFieldText(e.target.value)}
                        />
                    </div>
                    <div>
                        <label className="text-sm font-semibold text-gray-900">WooCommerce Meta</label>
                        <p className="text-xs text-gray-500 mb-2">Example: billing_phone, shipping_city.</p>
                        <textarea
                            className="min-h-[120px] w-full rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500"
                            value={wooFieldText}
                            onChange={(e) => setWooFieldText(e.target.value)}
                        />
                    </div>
                </div>
            </SettingsCard>

            <SettingsCard
                title="Registration & Login"
                description="Control how users enter your ecosystem via the API."
                onSave={onSave}
            >
                <ToggleInput
                    id="allow_registration_via_api"
                    label="Allow Registration"
                    description="Enable POST /register endpoint."
                    value={!!options.allow_registration_via_api}
                    setOption={updateOption}
                />
                <ToggleInput
                    id="auto_login_after_register"
                    label="Auto Login After Register"
                    description="Immediately issue a token after successful signup."
                    value={!!options.auto_login_after_register}
                    setOption={updateOption}
                />
            </SettingsCard>

            <SettingsCard
                title="Role-Based Access"
                description="Restrict plugin tools to specific roles."
                onSave={onSave}
            >
                <MultiSelectInput
                    id="allowed_roles"
                    label="Roles allowed to manage the plugin"
                    description="At least one role (administrator is recommended)."
                    values={options.allowed_roles || []}
                    options={availableRoleOptions}
                    setOption={updateOption}
                />
            </SettingsCard>

            <SettingsCard
                title="Endpoint Access Rules"
                description="Override access level for each REST endpoint."
                onSave={onSave}
            >
                <div className="space-y-6">
                    {endpointRules.map((endpoint) => {
                        const rule = options.rbac_rules?.[endpoint.key] || { mode: 'public', roles: [] };
                        return (
                            <div key={endpoint.key} className="border border-gray-200 rounded-md p-4">
                                <p className="text-sm font-semibold text-gray-900">{endpoint.label}</p>
                                <div className="mt-3">
                                    <select
                                        className="block w-full rounded-md border-gray-300 shadow-sm focus:border-gray-500 focus:ring-gray-500 sm:max-w-xs"
                                        value={rule.mode || 'public'}
                                        onChange={(e) => updateRbacRule(endpoint.key, { mode: e.target.value })}
                                    >
                                        {Object.entries(accessModes).map(([key, label]) => (
                                            <option key={key} value={key}>{label}</option>
                                        ))}
                                    </select>
                                </div>
                                {rule.mode === 'roles' && (
                                    <div className="mt-4">
                <MultiSelectInput
                                            id={`${endpoint.key}_roles`}
                                            label="Allowed Roles"
                                            description="Only these roles can access the endpoint."
                                            values={rule.roles || []}
                                            options={roleOptions}
                                            setOption={(value) => updateRbacRule(endpoint.key, { roles: value })}
                                        />
                                    </div>
                                )}
                            </div>
                        );
                    })}
                </div>
            </SettingsCard>
        </SettingsLayout>
    );
};

const convertSecondsToFields = (seconds = 3600) => {
    if (seconds % 86400 === 0) {
        return { value: seconds / 86400, unit: 'days' };
    }
    if (seconds % 3600 === 0) {
        return { value: seconds / 3600, unit: 'hours' };
    }
    return { value: Math.max(1, Math.round(seconds / 60)), unit: 'minutes' };
};

const convertFieldsToSeconds = ({ value, unit }) => {
    const safeValue = Math.max(1, parseInt(value, 10) || 1);
    if (unit === 'days') {
        return safeValue * 86400;
    }
    if (unit === 'hours') {
        return safeValue * 3600;
    }
    return safeValue * 60;
};

const listToMultiline = (list = []) => Array.isArray(list) ? list.join('\n') : '';

const parseListInput = (value = '') =>
    value
        .split(/[\n,]/)
        .map((item) => item.trim())
        .filter((item, index, self) => item && self.indexOf(item) === index);

export default GeneralSettings;