import React, { useState, useEffect, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { Zap, Plus, Trash2, Edit2, Eye, EyeOff, RefreshCw, Settings, Copy, Check } from 'lucide-react';
import { dataAPI } from '../infrastructure/api/data';
import { SYSTEM_TABLE_NAMES, FIELDS_SYSTEM_CONNECTEDAPP, SystemConnectedApp } from '@nexuscrm/generated-schema';
import { ConfirmationModal } from '@nexuscrm/salesforce-crm-standard-frontend/platform/components/ui';
import { useErrorToast, useSuccessToast } from '@nexuscrm/salesforce-crm-standard-frontend/platform/components/ui';
import { formatApiError } from '@nexuscrm/host-sdk';
import { PowerList, PowerListColumn } from '@nexuscrm/salesforce-crm-standard-frontend/platform/components/ui';
import { Badge } from '@nexuscrm/salesforce-crm-standard-frontend/platform/components/ui';
import { Tooltip } from '@nexuscrm/salesforce-crm-standard-frontend/platform/components/ui';
import { tryBuildSetupCapabilityChildPath } from '../core/navigation/setupPagePaths';
import { useApp } from '@nexuscrm/host-sdk';

// ─────────────────────────────────────────────────────────────────────────────
// Types
// ─────────────────────────────────────────────────────────────────────────────

type ConnectedApp = SystemConnectedApp;

interface ConnectedAppFormData {
    Name: string;
    ConsumerKey: string;
    ConsumerSecret: string;
    CallbackUrl?: string;
    RedirectUris: string;
    Scopes: string;
    ClientType: 'confidential' | 'public';
    RequirePkce: boolean;
    TokenEndpointAuthMethod: 'client_secret_post' | 'none';
    AllowedGrantTypes: string;
    ConsentPolicy: 'prompt' | 'trusted' | 'admin_preapproved';
    IssueRefreshTokens: boolean;
    PublisherName: string;
    SupportUrl: string;
    IsActive: boolean;
}

const CONFIDENTIAL_SCOPE_OPTIONS = ['api', 'api.read', 'chatter_api', 'openid'];
const PUBLIC_SCOPE_DISALLOWED_OPTIONS = new Set(CONFIDENTIAL_SCOPE_OPTIONS.concat('full'));
function p1PublicConsentPolicy(policy: ConnectedAppFormData['ConsentPolicy']): ConnectedAppFormData['ConsentPolicy'] {
    return policy === 'admin_preapproved' ? 'admin_preapproved' : 'trusted';
}

const EMPTY_FORM: ConnectedAppFormData = {
    Name: '',
    ConsumerKey: '',
    ConsumerSecret: '',
    CallbackUrl: '',
    RedirectUris: '',
    Scopes: '',
    ClientType: 'confidential',
    RequirePkce: false,
    TokenEndpointAuthMethod: 'client_secret_post',
    AllowedGrantTypes: 'authorization_code password client_credentials',
    ConsentPolicy: 'prompt',
    IssueRefreshTokens: false,
    PublisherName: '',
    SupportUrl: '',
    IsActive: true,
};

// ─────────────────────────────────────────────────────────────────────────────
// Helper: generate a random key/secret for setup-time copy.
// ─────────────────────────────────────────────────────────────────────────────

function generateKey(): string {
    const bytes = new Uint8Array(32);
    globalThis.crypto.getRandomValues(bytes);
    return btoa(String.fromCharCode(...bytes)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}

// ─────────────────────────────────────────────────────────────────────────────
// Helper: the edit-mode secret placeholder.
//
// Purely decorative. The stored value is a bcrypt hash (the plaintext is
// discarded at write time), so there is no ciphertext to mask and no prefix or
// suffix of the real secret that could be shown here. The dots say only "a
// secret exists and is hidden"; they deliberately carry no reveal affordance,
// because no reveal path exists anywhere in the platform.
// ─────────────────────────────────────────────────────────────────────────────

const SECRET_PLACEHOLDER = '•'.repeat(24);

const CopyButton: React.FC<{ value: string; label?: string }> = ({ value, label = 'Copy' }) => {
    const [copied, setCopied] = useState(false);

    useEffect(() => {
        if (!copied) return;
        const timer = setTimeout(() => setCopied(false), 2000);
        return () => clearTimeout(timer);
    }, [copied]);

    return (
        <button
            type="button"
            onClick={async () => {
                try {
                    await globalThis.navigator.clipboard.writeText(value);
                    setCopied(true);
                } catch {
                    // Clipboard access can be denied; the value stays selectable on screen.
                }
            }}
            className="flex items-center gap-1 text-xs text-blue-600 hover:text-blue-700"
        >
            {copied ? <Check size={12} /> : <Copy size={12} />}
            {copied ? 'Copied' : label}
        </button>
    );
};

// ─────────────────────────────────────────────────────────────────────────────
// ConnectedAppFormModal
// ─────────────────────────────────────────────────────────────────────────────

interface ConnectedAppFormModalProps {
    isOpen: boolean;
    editing: ConnectedApp | null;
    onClose: () => void;
    onSave: (data: ConnectedAppFormData) => Promise<void>;
    onRotateSecret: (app: ConnectedApp) => Promise<string>;
    submitting: boolean;
}

const ConnectedAppFormModal: React.FC<ConnectedAppFormModalProps> = ({
    isOpen,
    editing,
    onClose,
    onSave,
    onRotateSecret,
    submitting,
}) => {
    const [form, setForm] = useState<ConnectedAppFormData>(EMPTY_FORM);
    const [showSecret, setShowSecret] = useState(false);
    const [errors, setErrors] = useState<Partial<Record<keyof ConnectedAppFormData, string>>>({});
    const [confirmingRotate, setConfirmingRotate] = useState(false);
    const [rotating, setRotating] = useState(false);
    const [rotateError, setRotateError] = useState<string | null>(null);
    // The plaintext of a freshly rotated secret, held in memory for this modal only.
    const [rotatedSecret, setRotatedSecret] = useState<string | null>(null);

    useEffect(() => {
        if (!isOpen) return;
        if (editing) {
            const clientType = (editing.ClientType === 'public' ? 'public' : 'confidential') as ConnectedAppFormData['ClientType'];
            setForm({
                Name: editing.Name,
                ConsumerKey: editing.ConsumerKey,
                ConsumerSecret: '',
                CallbackUrl: editing.CallbackUrl ?? '',
                RedirectUris: editing.RedirectUris ?? editing.CallbackUrl ?? '',
                Scopes: editing.Scopes ?? '',
                ClientType: clientType,
                RequirePkce: editing.RequirePkce ?? clientType === 'public',
                TokenEndpointAuthMethod: editing.TokenEndpointAuthMethod === 'none' ? 'none' : 'client_secret_post',
                AllowedGrantTypes: editing.AllowedGrantTypes ?? (clientType === 'public' ? 'authorization_code' : 'authorization_code password client_credentials'),
                ConsentPolicy: clientType === 'public'
                    ? p1PublicConsentPolicy(editing.ConsentPolicy as ConnectedAppFormData['ConsentPolicy'])
                    : editing.ConsentPolicy === 'trusted' || editing.ConsentPolicy === 'admin_preapproved' ? editing.ConsentPolicy : 'prompt',
                IssueRefreshTokens: editing.IssueRefreshTokens ?? false,
                PublisherName: editing.PublisherName ?? '',
                SupportUrl: editing.SupportUrl ?? '',
                IsActive: editing.IsActive,
            });
        } else {
            setForm({
                ...EMPTY_FORM,
                ConsumerKey: generateKey(),
                ConsumerSecret: generateKey(),
            });
        }
        setShowSecret(!editing); // show secret once on create
        setErrors({});
        setConfirmingRotate(false);
        setRotating(false);
        setRotateError(null);
        setRotatedSecret(null);
    }, [isOpen, editing]);

    if (!isOpen) return null;

    const validate = (): boolean => {
        const next: typeof errors = {};
        if (!form.Name.trim()) next.Name = 'Name is required';
        if (!form.ConsumerKey.trim()) next.ConsumerKey = 'Consumer Key is required';
        if (form.ClientType === 'confidential' && !editing && !form.ConsumerSecret.trim()) next.ConsumerSecret = 'Consumer Secret is required';
        if (form.ClientType === 'public') {
            if (!form.RedirectUris.trim() && !form.CallbackUrl?.trim()) next.RedirectUris = 'Redirect URI is required';
            const scopes = form.Scopes.split(/\s+/).filter(Boolean);
            if (scopes.length === 0) next.Scopes = 'Scope is required';
            if (scopes.some(scope => PUBLIC_SCOPE_DISALLOWED_OPTIONS.has(scope))) next.Scopes = 'Public apps cannot use broad OAuth scopes';
        }
        setErrors(next);
        return Object.keys(next).length === 0;
    };

    const handleSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        if (!validate()) return;
        await onSave(form);
    };

    const toggleScope = (scope: string) => {
        const current = form.Scopes ? form.Scopes.split(' ').filter(Boolean) : [];
        const next = current.includes(scope)
            ? current.filter(s => s !== scope)
            : [...current, scope];
        setForm(f => ({ ...f, Scopes: next.join(' ') }));
    };

    const selectedScopes = form.Scopes ? form.Scopes.split(' ').filter(Boolean) : [];
    const scopeOptions = CONFIDENTIAL_SCOPE_OPTIONS;

    return (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
            <div className="bg-white rounded-xl shadow-2xl w-full max-w-lg mx-4 overflow-hidden">
                <div className="px-6 py-4 border-b border-slate-200">
                    <h2 className="text-lg font-semibold text-slate-800">
                        {editing ? 'Edit Connected App' : 'New Connected App'}
                    </h2>
                </div>

                <form id="connected-app-form" onSubmit={handleSubmit} className="px-6 py-4 space-y-4 max-h-[70vh] overflow-y-auto">
                    {/* Name */}
                    <div>
                        <label className="block text-sm font-medium text-slate-700 mb-1">
                            Name <span className="text-red-500">*</span>
                        </label>
                        <input
                            type="text"
                            value={form.Name}
                            onChange={e => setForm(f => ({ ...f, Name: e.target.value }))}
                            className={`w-full px-3 py-2 border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.Name ? 'border-red-400' : 'border-slate-300'}`}
                            placeholder="My Integration App"
                        />
                        {errors.Name && <p className="mt-1 text-xs text-red-500">{errors.Name}</p>}
                    </div>

                    {/* Consumer Key */}
                    <div>
                        <div className="flex items-center justify-between mb-1">
                            <label className="block text-sm font-medium text-slate-700">
                                Consumer Key <span className="text-red-500">*</span>
                            </label>
                            {!editing && (
                                <button
                                    type="button"
                                    onClick={() => setForm(f => ({ ...f, ConsumerKey: generateKey() }))}
                                    className="flex items-center gap-1 text-xs text-blue-600 hover:text-blue-700"
                                >
                                    <RefreshCw size={12} /> Regenerate
                                </button>
                            )}
                        </div>
                        <input
                            type="text"
                            value={form.ConsumerKey}
                            onChange={e => !editing && setForm(f => ({ ...f, ConsumerKey: e.target.value }))}
                            readOnly={!!editing}
                            className={`w-full px-3 py-2 border rounded-lg text-sm font-mono focus:outline-none focus:ring-2 focus:ring-blue-500 ${editing ? 'bg-slate-50 text-slate-500' : ''} ${errors.ConsumerKey ? 'border-red-400' : 'border-slate-300'}`}
                        />
                        {editing && (
                            <p className="mt-1 text-xs text-slate-400">Consumer Key cannot be changed after creation.</p>
                        )}
                        {errors.ConsumerKey && <p className="mt-1 text-xs text-red-500">{errors.ConsumerKey}</p>}
                    </div>

                    {/* Client Type */}
                    <div>
                        <label className="block text-sm font-medium text-slate-700 mb-2">Client Type</label>
                        <div className="inline-flex rounded-lg border border-slate-300 overflow-hidden">
                            {(['confidential', 'public'] as const).map(clientType => (
                                <button
                                    key={clientType}
                                    type="button"
                                    onClick={() => {
                                        // Selecting the active type must stay inert: the
                                        // confidential branch mints a secret, so re-clicking it
                                        // would stage a credential replacement out of nothing.
                                        if (form.ClientType === clientType) return;
                                        // Switching to confidential mints a secret that is written
                                        // on save. It can never be read back, so it must be shown.
                                        setShowSecret(clientType === 'confidential');
                                        setForm(f => ({
                                            ...f,
                                            ClientType: clientType,
                                            ConsumerSecret: clientType === 'public' ? '' : f.ConsumerSecret || generateKey(),
                                            Scopes: clientType === 'public' ? '' : f.Scopes,
                                            RequirePkce: clientType === 'public' ? true : f.RequirePkce,
                                            TokenEndpointAuthMethod: clientType === 'public' ? 'none' : 'client_secret_post',
                                            AllowedGrantTypes: clientType === 'public' ? 'authorization_code' : 'authorization_code password client_credentials',
                                            ConsentPolicy: clientType === 'public' ? p1PublicConsentPolicy(f.ConsentPolicy) : f.ConsentPolicy,
                                        }));
                                    }}
                                    className={`px-3 py-2 text-sm font-medium capitalize ${form.ClientType === clientType
                                        ? 'bg-blue-600 text-white'
                                        : 'bg-white text-slate-600 hover:bg-slate-50'
                                        }`}
                                >
                                    {clientType}
                                </button>
                            ))}
                        </div>
                    </div>

                    {/* Consumer Secret */}
                    {form.ClientType === 'confidential' && (
                    <div>
                        {/*
                          * The placeholder stands for a *stored* secret, so it is keyed on the
                          * form holding no plaintext — not on `editing`. Switching client type
                          * to confidential mints a secret (`f.ConsumerSecret || generateKey()`),
                          * including on a public -> confidential edit and on a confidential ->
                          * public -> confidential round trip. Keying on `editing` alone hid that
                          * value behind the dots and let Save submit a secret the admin never
                          * saw and can never recover.
                          */}
                        {editing && !form.ConsumerSecret ? (
                            <>
                                {/*
                                  * Edit mode is display-only. The secret is write-only: it is
                                  * stored as a bcrypt hash and the plaintext is discarded, so
                                  * there is nothing to load and no endpoint that could reveal
                                  * it. A text input here would not read the secret back — it
                                  * would silently replace it, and ConsumerSecret is a
                                  * session-invalidating field, so an admin expecting to "view"
                                  * a credential would instead revoke every token and session
                                  * for the app. Replacement is therefore an explicit,
                                  * confirmed Rotate action rather than a typeable field.
                                  */}
                                <div className="flex items-center justify-between mb-1">
                                    <label className="block text-sm font-medium text-slate-700">
                                        Consumer Secret
                                    </label>
                                    <button
                                        type="button"
                                        onClick={() => {
                                            setRotateError(null);
                                            setConfirmingRotate(true);
                                        }}
                                        disabled={rotating || submitting}
                                        className="flex items-center gap-1 text-xs text-blue-600 hover:text-blue-700 disabled:opacity-50"
                                    >
                                        <RefreshCw size={12} /> Rotate secret
                                    </button>
                                </div>
                                <div
                                    aria-label="Consumer Secret is hidden and cannot be retrieved"
                                    className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm font-mono bg-slate-50 text-slate-400 select-none"
                                >
                                    {SECRET_PLACEHOLDER}
                                </div>
                                <p className="mt-1 text-xs text-slate-400">
                                    Stored as a hash and cannot be retrieved. Rotate to issue a new secret.
                                </p>
                                {rotatedSecret && (
                                    <div className="mt-2 rounded-lg border border-amber-300 bg-amber-50 px-3 py-2">
                                        <div className="flex items-center justify-between mb-1">
                                            <span className="text-xs font-medium text-amber-800">New Consumer Secret</span>
                                            <CopyButton value={rotatedSecret} />
                                        </div>
                                        <p className="text-sm font-mono break-all text-slate-800">{rotatedSecret}</p>
                                        <p className="mt-1 text-xs text-amber-700">
                                            This is the only time this secret is shown. Copy it now — it is stored as a
                                            hash and cannot be retrieved later. It is already in effect; every previous
                                            token and session for this app has been revoked.
                                        </p>
                                    </div>
                                )}
                            </>
                        ) : (
                            <>
                                <div className="flex items-center justify-between mb-1">
                                    <label className="block text-sm font-medium text-slate-700">
                                        Consumer Secret <span className="text-red-500">*</span>
                                    </label>
                                    <div className="flex items-center gap-3">
                                        <CopyButton value={form.ConsumerSecret} />
                                        <button
                                            type="button"
                                            onClick={() => setShowSecret(s => !s)}
                                            className="flex items-center gap-1 text-xs text-slate-500 hover:text-slate-700"
                                        >
                                            {showSecret ? <EyeOff size={12} /> : <Eye size={12} />}
                                            {showSecret ? 'Hide' : 'Show'}
                                        </button>
                                    </div>
                                </div>
                                <input
                                    aria-label="Consumer Secret"
                                    type={showSecret ? 'text' : 'password'}
                                    value={form.ConsumerSecret}
                                    onChange={e => setForm(f => ({ ...f, ConsumerSecret: e.target.value }))}
                                    className={`w-full px-3 py-2 border rounded-lg text-sm font-mono focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.ConsumerSecret ? 'border-red-400' : 'border-slate-300'}`}
                                />
                                <p className="mt-1 text-xs text-amber-600">
                                    {editing
                                        ? 'This new secret is applied when you save. Copy it now — it is stored as a hash and cannot be retrieved later, and saving revokes every existing token and session for this app.'
                                        : 'Copy this secret now — it is stored as a hash and cannot be retrieved later.'}
                                </p>
                                {errors.ConsumerSecret && <p className="mt-1 text-xs text-red-500">{errors.ConsumerSecret}</p>}
                            </>
                        )}
                    </div>
                    )}

                    {/* Callback URL */}
                    <div>
                        <label className="block text-sm font-medium text-slate-700 mb-1">Redirect URIs</label>
                        <textarea
                            rows={3}
                            value={form.RedirectUris}
                            onChange={e => setForm(f => ({ ...f, RedirectUris: e.target.value, CallbackUrl: e.target.value.split(/\s|,/).find(Boolean) ?? '' }))}
                            className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
                            placeholder="https://example.com/oauth/callback"
                        />
                        {errors.RedirectUris && <p className="mt-1 text-xs text-red-500">{errors.RedirectUris}</p>}
                    </div>

                    {/* Scopes */}
                    <div>
                        <label className="block text-sm font-medium text-slate-700 mb-2">Scopes</label>
                        {form.ClientType === 'public' ? (
                            <input
                                type="text"
                                value={form.Scopes}
                                onChange={e => setForm(f => ({ ...f, Scopes: e.target.value }))}
                                className={`w-full px-3 py-2 border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.Scopes ? 'border-red-400' : 'border-slate-300'}`}
                            />
                        ) : (
                            <div className="flex flex-wrap gap-2">
                                {scopeOptions.map(scope => (
                                    <button
                                        key={scope}
                                        type="button"
                                        onClick={() => toggleScope(scope)}
                                        className={`px-3 py-1 rounded-full text-xs font-medium border transition-colors ${selectedScopes.includes(scope)
                                            ? 'bg-blue-600 text-white border-blue-600'
                                            : 'bg-white text-slate-600 border-slate-300 hover:border-blue-400'
                                            }`}
                                    >
                                        {scope}
                                    </button>
                                ))}
                            </div>
                        )}
                        {errors.Scopes && <p className="mt-1 text-xs text-red-500">{errors.Scopes}</p>}
                    </div>

                    {/* OAuth Policy */}
                    <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
                        <div>
                            <label className="block text-sm font-medium text-slate-700 mb-1">Consent Policy</label>
                            <select
                                value={form.ConsentPolicy}
                                onChange={e => setForm(f => ({ ...f, ConsentPolicy: e.target.value as ConnectedAppFormData['ConsentPolicy'] }))}
                                className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
                            >
                                {form.ClientType !== 'public' && <option value="prompt">Prompt</option>}
                                <option value="trusted">Trusted</option>
                                <option value="admin_preapproved">Admin Preapproved</option>
                            </select>
                        </div>
                        <div>
                            <label className="block text-sm font-medium text-slate-700 mb-1">Publisher</label>
                            <input
                                type="text"
                                value={form.PublisherName}
                                onChange={e => setForm(f => ({ ...f, PublisherName: e.target.value }))}
                                className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
                            />
                        </div>
                    </div>

                    {/* IsActive */}
                    <div className="flex items-center gap-3">
                        <button
                            type="button"
                            role="switch"
                            aria-checked={form.IsActive}
                            onClick={() => setForm(f => ({ ...f, IsActive: !f.IsActive }))}
                            className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 ${form.IsActive ? 'bg-blue-600' : 'bg-slate-300'}`}
                        >
                            <span
                                className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${form.IsActive ? 'translate-x-6' : 'translate-x-1'}`}
                            />
                        </button>
                        <span className="text-sm text-slate-700">Active</span>
                    </div>
                </form>

                <div className="px-6 py-4 border-t border-slate-200 flex items-center justify-end gap-3">
                    <button
                        type="button"
                        onClick={onClose}
                        disabled={submitting}
                        className="px-4 py-2 text-sm font-medium text-slate-700 bg-white border border-slate-300 rounded-lg hover:bg-slate-50 disabled:opacity-50"
                    >
                        Cancel
                    </button>
                    <button
                        type="submit"
                        form="connected-app-form"
                        disabled={submitting}
                        className="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 flex items-center gap-2"
                    >
                        {submitting && <span className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />}
                        {editing ? 'Save Changes' : 'Create'}
                    </button>
                </div>
            </div>

            {editing && (
                <ConfirmationModal
                    isOpen={confirmingRotate}
                    onClose={() => {
                        if (rotating) return;
                        setConfirmingRotate(false);
                        setRotateError(null);
                    }}
                    onConfirm={async () => {
                        setRotating(true);
                        setRotateError(null);
                        try {
                            const nextSecret = await onRotateSecret(editing);
                            setRotatedSecret(nextSecret);
                            setConfirmingRotate(false);
                        } catch (err: unknown) {
                            setRotateError(formatApiError(err).message);
                        } finally {
                            setRotating(false);
                        }
                    }}
                    title="Rotate consumer secret?"
                    variant="danger"
                    // Nested inside the form modal's own overlay; BaseModal
                    // documents this override for stacking above a parent modal.
                    className="z-[1000]"
                    confirmLabel="Rotate secret"
                    loading={rotating}
                    errorMessage={rotateError}
                    message={
                        <span>
                            A new secret for <strong>{editing.Name}</strong> is generated and applied
                            immediately — this does not wait for Save, and it cannot be undone.
                            Every access token, refresh token, and session for this app is revoked,
                            and any integration still using the current secret stops working until it
                            is updated. The current secret cannot be recovered.
                        </span>
                    }
                />
            )}
        </div>
    );
};

// ─────────────────────────────────────────────────────────────────────────────
// ConnectedAppManager (main page component)
// ─────────────────────────────────────────────────────────────────────────────

export const ConnectedAppManager: React.FC = () => {
    const navigate = useNavigate();
    const { currentFrontendAppId } = useApp();
    const errorToast = useErrorToast();
    const successToast = useSuccessToast();

    const [apps, setApps] = useState<ConnectedApp[]>([]);
    const [loading, setLoading] = useState(true);
    const [showForm, setShowForm] = useState(false);
    const [editing, setEditing] = useState<ConnectedApp | null>(null);
    const [deleting, setDeleting] = useState<ConnectedApp | null>(null);
    const [submitting, setSubmitting] = useState(false);

    const loadApps = useCallback(async () => {
        setLoading(true);
        try {
            const records = await dataAPI.query<ConnectedApp>({
                objectApiName: SYSTEM_TABLE_NAMES.SYSTEM_CONNECTEDAPP,
                selectFields: [
                    FIELDS_SYSTEM_CONNECTEDAPP.ID,
                    FIELDS_SYSTEM_CONNECTEDAPP.NAME,
                    FIELDS_SYSTEM_CONNECTEDAPP.CONSUMER_KEY,
                    FIELDS_SYSTEM_CONNECTEDAPP.CALLBACK_URL,
                    FIELDS_SYSTEM_CONNECTEDAPP.REDIRECT_URIS,
                    FIELDS_SYSTEM_CONNECTEDAPP.SCOPES,
                    FIELDS_SYSTEM_CONNECTEDAPP.CLIENT_TYPE,
                    FIELDS_SYSTEM_CONNECTEDAPP.REQUIRE_PKCE,
                    FIELDS_SYSTEM_CONNECTEDAPP.TOKEN_ENDPOINT_AUTH_METHOD,
                    FIELDS_SYSTEM_CONNECTEDAPP.ALLOWED_GRANT_TYPES,
                    FIELDS_SYSTEM_CONNECTEDAPP.CONSENT_POLICY,
                    FIELDS_SYSTEM_CONNECTEDAPP.ISSUE_REFRESH_TOKENS,
                    FIELDS_SYSTEM_CONNECTEDAPP.PUBLISHER_NAME,
                    FIELDS_SYSTEM_CONNECTEDAPP.SUPPORT_URL,
                    FIELDS_SYSTEM_CONNECTEDAPP.IS_ACTIVE,
                ],
            });
            setApps(records);
        } catch (err: unknown) {
            errorToast(`Failed to load connected apps: ${formatApiError(err).message}`);
        } finally {
            setLoading(false);
        }
    }, [errorToast]);

    useEffect(() => {
        loadApps();
    }, [loadApps]);

    const handleOpenCreate = () => {
        setEditing(null);
        setShowForm(true);
    };

    const handleOpenEdit = (app: ConnectedApp) => {
        setEditing(app);
        setShowForm(true);
    };

    // Rotation writes the new secret on its own rather than riding along with
    // Save: it is irreversible and revokes every live token, so it must not be
    // bundled into an unrelated field edit, and the plaintext shown to the admin
    // afterwards has to be the value that is actually in effect.
    const handleRotateSecret = useCallback(async (app: ConnectedApp): Promise<string> => {
        const nextSecret = generateKey();
        await dataAPI.updateRecord(
            SYSTEM_TABLE_NAMES.SYSTEM_CONNECTEDAPP,
            app.Id,
            { ConsumerSecret: nextSecret }
        );
        return nextSecret;
    }, []);

    const handleSave = async (data: ConnectedAppFormData) => {
        setSubmitting(true);
        try {
            const callbackUrl = data.RedirectUris.split(/\s|,/).find(Boolean) ?? data.CallbackUrl ?? '';
            const basePayload = {
                Name: data.Name,
                CallbackUrl: callbackUrl,
                RedirectUris: data.RedirectUris,
                Scopes: data.Scopes,
                ClientType: data.ClientType,
                RequirePkce: data.ClientType === 'public' ? true : data.RequirePkce,
                TokenEndpointAuthMethod: data.ClientType === 'public' ? 'none' : data.TokenEndpointAuthMethod,
                // Preserve refresh-token config for public apps rather than forcing it off.
                // Server-side, refresh issuance is gated by IssueRefreshTokens + the
                // refresh_token grant (never offline_access), so source-backed public apps
                // (e.g. Public BI) may legitimately enable it. Hardcoding these on save let a
                // routine edit silently downgrade a refresh-enabled app; the form loads the
                // real values when editing, so preserving them is correct. (New public apps
                // still default to authorization_code / no refresh — there is no UI control to
                // change them, and the backend enforces the public-client grant allowlist.)
                AllowedGrantTypes: data.AllowedGrantTypes,
                ConsentPolicy: data.ClientType === 'public' ? p1PublicConsentPolicy(data.ConsentPolicy) : data.ConsentPolicy,
                IssueRefreshTokens: data.IssueRefreshTokens,
                PublisherName: data.PublisherName,
                SupportUrl: data.SupportUrl,
                IsActive: data.IsActive,
            };
            if (editing) {
                const updatePayload: Record<string, unknown> = { ...basePayload };
                if (data.ClientType === 'public') {
                    updatePayload.ConsumerSecret = '';
                } else if (data.ConsumerSecret.trim()) {
                    updatePayload.ConsumerSecret = data.ConsumerSecret;
                }
                await dataAPI.updateRecord(
                    SYSTEM_TABLE_NAMES.SYSTEM_CONNECTEDAPP,
                    editing.Id,
                    updatePayload
                );
                successToast('Connected App updated');
            } else {
                const createPayload: Partial<ConnectedApp> = {
                    ...basePayload,
                    ConsumerKey: data.ConsumerKey,
                };
                if (data.ClientType === 'confidential') {
                    createPayload.ConsumerSecret = data.ConsumerSecret;
                }
                await dataAPI.createRecord<ConnectedApp>(
                    SYSTEM_TABLE_NAMES.SYSTEM_CONNECTEDAPP,
                    createPayload
                );
                successToast('Connected App created');
            }
            setShowForm(false);
            setEditing(null);
            await loadApps();
        } catch (err: unknown) {
            errorToast(`Failed to save: ${formatApiError(err).message}`);
        } finally {
            setSubmitting(false);
        }
    };

    const handleToggleActive = async (app: ConnectedApp) => {
        try {
            await dataAPI.updateRecord(
                SYSTEM_TABLE_NAMES.SYSTEM_CONNECTEDAPP,
                app.Id,
                { IsActive: !app.IsActive }
            );
            successToast(`Connected App ${app.IsActive ? 'deactivated' : 'activated'}`);
            await loadApps();
        } catch (err: unknown) {
            errorToast(`Failed to update status: ${formatApiError(err).message}`);
        }
    };

    const handleConfirmDelete = async () => {
        if (!deleting) return;
        try {
            await dataAPI.deleteRecord(SYSTEM_TABLE_NAMES.SYSTEM_CONNECTEDAPP, deleting.Id);
            successToast('Connected App deleted');
            setDeleting(null);
            await loadApps();
        } catch (err: unknown) {
            errorToast(`Failed to delete: ${formatApiError(err).message}`);
        }
    };

    const columns: PowerListColumn<ConnectedApp>[] = [
        {
            key: 'Name',
            label: 'Name',
            minWidth: '160px',
            render: (val) => (
                <span className="font-medium text-slate-900 dark:text-white">
                    {val ? String(val) : '—'}
                </span>
            ),
        },
        {
            key: 'ConsumerKey',
            label: 'Consumer Key',
            minWidth: '220px',
            render: (val) => (
                <span className="font-mono text-xs text-slate-600 dark:text-gray-400 truncate block max-w-[220px]">
                    {val ? String(val) : '—'}
                </span>
            ),
        },
        {
            key: 'Scopes',
            label: 'Scopes',
            minWidth: '160px',
            render: (val) => {
                const scopes = val ? String(val).split(' ').filter(Boolean) : [];
                if (!scopes.length) return <span className="text-gray-400">—</span>;
                return (
                    <div className="flex flex-wrap gap-1">
                        {scopes.map(s => (
                            <Badge key={s} variant="info">{s}</Badge>
                        ))}
                    </div>
                );
            },
        },
        {
            key: 'ClientType',
            label: 'Type',
            minWidth: '110px',
            render: (val) => (
                <Badge variant={val === 'public' ? 'warning' : 'neutral'}>
                    {val === 'public' ? 'Public' : 'Confidential'}
                </Badge>
            ),
        },
        {
            key: 'IsActive',
            label: 'Status',
            minWidth: '90px',
            render: (val) => (
                <Badge variant={val ? 'success' : 'neutral'}>
                    {val ? 'Active' : 'Inactive'}
                </Badge>
            ),
        },
    ];

    const renderActions = (app: ConnectedApp) => (
        <div className="flex items-center justify-end gap-1">
            <Tooltip content="Manage" position="top">
                <button
                    onClick={() => navigate(tryBuildSetupCapabilityChildPath(currentFrontendAppId, 'connectedApps', app.Id) ?? '/')}
                    className="p-1.5 text-gray-400 hover:text-indigo-500 hover:bg-indigo-50 dark:hover:bg-indigo-900/20 rounded-lg transition-colors"
                >
                    <Settings size={16} />
                </button>
            </Tooltip>
            <Tooltip content={app.IsActive ? 'Deactivate' : 'Activate'} position="top">
                <button
                    onClick={() => handleToggleActive(app)}
                    className={`p-1.5 rounded-lg transition-colors ${app.IsActive
                        ? 'text-gray-400 hover:text-amber-500 hover:bg-amber-50 dark:hover:bg-amber-900/20'
                        : 'text-gray-400 hover:text-green-500 hover:bg-green-50 dark:hover:bg-green-900/20'
                        }`}
                >
                    <Zap size={16} />
                </button>
            </Tooltip>
            <Tooltip content="Edit" position="top">
                <button
                    onClick={() => handleOpenEdit(app)}
                    className="p-1.5 text-gray-400 hover:text-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg transition-colors"
                >
                    <Edit2 size={16} />
                </button>
            </Tooltip>
            <Tooltip content="Delete" position="top">
                <button
                    onClick={() => setDeleting(app)}
                    className="p-1.5 text-gray-400 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-lg transition-colors"
                >
                    <Trash2 size={16} />
                </button>
            </Tooltip>
        </div>
    );

    return (
        <div className="max-w-7xl mx-auto p-6">
            <div className="flex items-center justify-between mb-8">
                <div className="flex items-center gap-4">
                    <div className="p-3 bg-indigo-100 rounded-lg">
                        <Zap className="text-indigo-600" size={32} />
                    </div>
                    <div>
                        <h1 className="text-2xl font-bold text-slate-800">Connected Apps</h1>
                        <p className="text-slate-500">Manage OAuth connected applications and their access.</p>
                    </div>
                </div>
                <button
                    onClick={handleOpenCreate}
                    className="flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-medium shadow-sm transition-colors"
                >
                    <Plus size={18} />
                    New Connected App
                </button>
            </div>

            <PowerList<ConnectedApp>
                data={apps}
                columns={columns}
                loading={loading}
                rowKey={(app) => app.Id}
                searchable
                searchPlaceholder="Search connected apps..."
                defaultSort={{ key: 'Name', direction: 'asc' }}
                emptyIcon={<Zap className="w-12 h-12" />}
                emptyTitle="No Connected Apps"
                emptyMessage="Create your first connected app to enable OAuth integrations."
                emptyAction={{ label: 'New Connected App', onClick: handleOpenCreate }}
                actions={renderActions}
                ariaLabel="Connected Apps list"
            />

            <ConnectedAppFormModal
                isOpen={showForm}
                editing={editing}
                onClose={() => { setShowForm(false); setEditing(null); }}
                onSave={handleSave}
                onRotateSecret={handleRotateSecret}
                submitting={submitting}
            />

            <ConfirmationModal
                isOpen={!!deleting}
                onClose={() => setDeleting(null)}
                onConfirm={handleConfirmDelete}
                title="Delete Connected App"
                message={`Are you sure you want to delete "${deleting?.Name}"? Any integrations using this app will stop working.`}
                confirmLabel="Delete"
                variant="danger"
            />
        </div>
    );
};
