import BotAuthForm from '@/components/bot/BotAuthForm';
import BotPlatformSelector from '@/components/bot/BotPlatformSelector';
import { BotCard, useBotModelDialog } from '@/components/bot';
import EmptyStateGuide from '@/components/EmptyStateGuide';
import { PageLayout } from '@/components/PageLayout';
import PlatformGuide from '@/components/remote-control/PlatformGuide';
import UnifiedCard from '@/components/UnifiedCard';
import { api } from '@/services/api';
import type { BotPlatformConfig, BotSettings } from '@/types/bot';
import type { Provider } from '@/types/provider';
import { Add } from '@mui/icons-material';
import {
    Alert,
    Box,
    Button,
    CircularProgress,
    FormControlLabel,
    FormHelperText,
    Modal,
    Snackbar,
    Stack,
    Switch,
    TextField,
    Typography,
} from '@mui/material';
import { useCallback, useEffect, useState } from 'react';

const BotPage = () => {
    // Bot settings state
    const [bots, setBots] = useState<BotSettings[]>([]);

    // Bot platforms config state
    const [botPlatforms, setBotPlatforms] = useState<BotPlatformConfig[]>([]);
    const [currentPlatformConfig, setCurrentPlatformConfig] = useState<BotPlatformConfig | null>(null);

    // Bot form draft state for add/edit dialog
    const [botDialogMode, setBotDialogMode] = useState<'add' | 'edit' | 'qr-binding'>('add');
    const [botEditUuid, setBotEditUuid] = useState<string | null>(null);
    const [botNameDraft, setBotNameDraft] = useState('');
    const [botPlatformDraft, setBotPlatformDraft] = useState('telegram');
    const [botAuthDraft, setBotAuthDraft] = useState<Record<string, string>>({});
    const [botProxyDraft, setBotProxyDraft] = useState('');
    const [botChatIdDraft, setBotChatIdDraft] = useState('');
    const [botAllowlistDraft, setBotAllowlistDraft] = useState('');
    const [botRequirePairingDraft, setBotRequirePairingDraft] = useState(true);
    // Whether the operator manually flipped the pairing switch in this session.
    // Mirrors the platform default until the user touches it.
    const [botRequirePairingTouched, setBotRequirePairingTouched] = useState(false);

    const [botLoading, setBotLoading] = useState(false);
    const [botSaving, setBotSaving] = useState(false);
    const [botPlatformsLoading, setBotPlatformsLoading] = useState(false);
    const [botTokenDialogOpen, setBotTokenDialogOpen] = useState(false);
    const [guideExpanded, setGuideExpanded] = useState<string | false>(false);

    // Toggle loading state
    const [togglingBotUuid, setTogglingBotUuid] = useState<string | null>(null);
    const [restartingBotUuid, setRestartingBotUuid] = useState<string | null>(null);

    // Snackbar notification state
    const [snackbar, setSnackbar] = useState<{
        open: boolean;
        message: string;
        severity: 'success' | 'error' | 'info' | 'warning';
    }>({ open: false, message: '', severity: 'success' });

    // Notification helper - errors require manual dismissal, others auto-hide
    const showNotification = useCallback((message: string, severity: 'success' | 'error' | 'info' | 'warning' = 'success') => {
        setSnackbar({ open: true, message, severity });
    }, []);

    // Providers for model selection
    const [providers, setProviders] = useState<Provider[]>([]);
    const [selectedBot, setSelectedBot] = useState<BotSettings | null>(null);

    useEffect(() => {
        loadBotPlatforms();
        loadBotSettings();
        loadProviders();
    }, []);

    // Load bot platforms configuration
    const loadBotPlatforms = useCallback(async () => {
        try {
            setBotPlatformsLoading(true);
            const data = await api.getImBotPlatforms();
            if (data?.success && data?.platforms) {
                setBotPlatforms(data.platforms);
            }
        } catch (err) {
            console.error('Failed to load bot platforms:', err);
        } finally {
            setBotPlatformsLoading(false);
        }
    }, []);

    const loadBotSettings = useCallback(async () => {
        try {
            setBotLoading(true);
            const data = await api.getImBotSettingsList();
            if (data?.success && Array.isArray(data.settings)) {
                setBots(data.settings);
            } else if (data?.success === false) {
                showNotification(data.error || 'Failed to load bot settings', 'error');
            }
        } catch (err) {
            console.error('Failed to load bot settings:', err);
            showNotification('Failed to load bot settings', 'error');
        } finally {
            setBotLoading(false);
        }
    }, []);

    const loadProviders = useCallback(async () => {
        const data = await api.getProviders();
        if (data?.success && data?.data) {
            setProviders(data.data);
        }
    }, []);

    // Update current platform config when platform draft changes
    useEffect(() => {
        if (botPlatformDraft && botPlatforms.length > 0) {
            const config = botPlatforms.find(p => p.platform === botPlatformDraft);
            if (config) {
                setCurrentPlatformConfig(config);
            }
        }
    }, [botPlatformDraft, botPlatforms]);

    // Mirrors bot.PlatformDefaultsRequirePairing (Go): token-DM platforms
    // default to TOFU pairing on; OAuth/QR platforms default off.
    const platformDefaultRequirePairing = (platform: string): boolean =>
        platform === 'telegram' || platform === 'discord' || platform === 'slack';

    // Bot handlers
    const handleOpenBotTokenDialog = useCallback((editUuid?: string) => {
        if (editUuid) {
            // Edit mode
            const bot = bots.find(b => b.uuid === editUuid);
            if (bot) {
                setBotDialogMode('edit');
                setBotEditUuid(editUuid);
                setBotNameDraft(bot.name || '');
                setBotPlatformDraft(bot.platform || 'telegram');
                setBotAuthDraft(bot.auth ? { ...bot.auth } : {});
                setBotProxyDraft(bot.proxy_url || '');
                setBotChatIdDraft(bot.chat_id || '');
                setBotAllowlistDraft((bot.bash_allowlist || []).join('\n'));
                // Hydrate require_pairing: explicit value wins, nil falls
                // back to the platform default. Once the user saves, the
                // value becomes explicit on the server.
                setBotRequirePairingDraft(
                    typeof bot.require_pairing === 'boolean'
                        ? bot.require_pairing
                        : platformDefaultRequirePairing(bot.platform || 'telegram'),
                );
                setBotRequirePairingTouched(false);
                // Set platform config
                const config = botPlatforms.find(p => p.platform === bot.platform);
                if (config) {
                    setCurrentPlatformConfig(config);
                }
            }
        } else {
            // Add mode
            setBotDialogMode('add');
            setBotEditUuid(null);
            setBotNameDraft('');
            setBotPlatformDraft('telegram');
            setBotAuthDraft({});
            setBotProxyDraft('');
            setBotChatIdDraft('');
            setBotAllowlistDraft('');
            setBotRequirePairingDraft(platformDefaultRequirePairing('telegram'));
            setBotRequirePairingTouched(false);
            // Set default platform config
            const config = botPlatforms.find(p => p.platform === 'telegram');
            if (config) {
                setCurrentPlatformConfig(config);
            }
        }
        setBotTokenDialogOpen(true);
    }, [bots, botPlatforms]);

    const handleSaveBotToken = async () => {
        setBotSaving(true);

        try {
            const allowlist = botAllowlistDraft
                .split(/[\n,]+/)
                .map((entry) => entry.trim())
                .filter((entry) => entry.length > 0);

            // Get platform config to validate required fields
            const platformConfig = botPlatforms.find(p => p.platform === botPlatformDraft);
            if (!platformConfig) {
                showNotification(`Unknown platform: ${botPlatformDraft}`, 'error');
                return;
            }

            // Special handling for QR auth type - create bot first, then bind with QR
            if (platformConfig.auth_type === 'qr' && botDialogMode === 'add') {
                // For QR auth, create bot without auth validation first
                const data = {
                    name: botNameDraft.trim() || `${botPlatformDraft} Bot`,
                    platform: botPlatformDraft,
                    auth_type: platformConfig.auth_type,
                    auth: {}, // Empty auth, will be filled by QR flow
                    proxy_url: botProxyDraft.trim(),
                    chat_id: botChatIdDraft.trim(),
                    bash_allowlist: allowlist,
                    enabled: false, // Don't enable until QR binding completes
                    require_pairing: botRequirePairingDraft,
                };

                const result = await api.createImBotSetting(data);

                if (result?.success === false) {
                    showNotification(result.error || 'Failed to create bot', 'error');
                    return;
                }

                // Reload bots to get the new UUID
                await loadBotSettings();

                // Switch to QR binding mode with the new bot's UUID
                // Backend returns SettingsResponse with { settings: { uuid: ... } }
                if (result?.settings?.uuid) {
                    setBotDialogMode('qr-binding');
                    setBotEditUuid(result.settings.uuid);
                    showNotification('Bot created. Please scan the QR code to complete binding.', 'info');
                }
                return;
            }

            // Validate required auth fields for non-QR auth types
            const missingFields = platformConfig.fields
                .filter(f => f.required && !botAuthDraft[f.key]?.trim())
                .map(f => f.label);

            if (missingFields.length > 0) {
                showNotification(`Missing required fields: ${missingFields.join(', ')}`, 'error');
                return;
            }

            const data = {
                name: botNameDraft.trim(),
                platform: botPlatformDraft,
                auth_type: platformConfig.auth_type,
                auth: botAuthDraft,
                proxy_url: botProxyDraft.trim(),
                chat_id: botChatIdDraft.trim(),
                bash_allowlist: allowlist,
                enabled: true,
                require_pairing: botRequirePairingDraft,
            };

            let result;
            if (botDialogMode === 'edit' && botEditUuid) {
                result = await api.updateImBotSetting(botEditUuid, data);
            } else {
                result = await api.createImBotSetting(data);
            }

            if (result?.success === false) {
                showNotification(result.error || 'Failed to save bot settings', 'error');
                return;
            }

            // Reload bots
            await loadBotSettings();

            showNotification(`Bot ${botDialogMode === 'edit' ? 'updated' : 'created'} successfully.`, 'success');
            setBotTokenDialogOpen(false);
        } catch (err) {
            console.error('Failed to save bot settings:', err);
            showNotification('Failed to save bot settings', 'error');
        } finally {
            setBotSaving(false);
        }
    };

    const handleBotToggle = useCallback(async (uuid: string, enabled: boolean) => {
        setTogglingBotUuid(uuid);
        try {
            const result = await api.toggleImBotSetting(uuid);
            if (result?.success) {
                showNotification(enabled ? 'Bot enabled' : 'Bot disabled', 'success');
                await loadBotSettings();
            } else {
                showNotification(`Failed to toggle bot: ${result?.error || 'Unknown error'}`, 'error');
            }
        } catch (err) {
            console.error('Failed to toggle bot:', err);
            showNotification('Failed to toggle bot', 'error');
        } finally {
            setTogglingBotUuid(null);
        }
    }, [loadBotSettings, showNotification]);

    const handleBotRestart = useCallback(async (uuid: string) => {
        setRestartingBotUuid(uuid);
        try {
            const result = await api.restartImBot(uuid);
            if (result?.success) {
                showNotification('Bot restarted', 'success');
                await loadBotSettings();
            } else {
                showNotification(`Failed to restart bot: ${result?.error || 'Unknown error'}`, 'error');
            }
        } catch (err) {
            console.error('Failed to restart bot:', err);
            showNotification('Failed to restart bot', 'error');
        } finally {
            setRestartingBotUuid(null);
        }
    }, [loadBotSettings, showNotification]);

    const handleDeleteBot = useCallback(async (uuid: string) => {
        try {
            const result = await api.deleteImBotSetting(uuid);
            if (result?.success) {
                showNotification('Bot deleted successfully', 'success');
                await loadBotSettings();
            } else {
                showNotification(`Failed to delete bot: ${result?.error}`, 'error');
            }
        } catch (err) {
            showNotification('Failed to delete bot', 'error');
        }
    }, [loadBotSettings, showNotification]);

    const handleQRBindingComplete = useCallback(async () => {
        // Reload bots to get the updated credentials
        await loadBotSettings();
        showNotification('Weixin bot bound successfully!', 'success');
        // Close the dialog
        setBotTokenDialogOpen(false);
    }, [loadBotSettings, showNotification]);

    const handleCWDChange = useCallback(async (botUuid: string, cwd: string) => {
        try {
            const result = await api.updateImbotSetting(botUuid, { default_cwd: cwd });
            if (result?.success) {
                // No notification needed for CWD change - it's a minor change
                await loadBotSettings();
            } else {
                showNotification(result?.error || 'Failed to update working directory', 'error');
            }
        } catch (err) {
            showNotification('Failed to update working directory', 'error');
        }
    }, [loadBotSettings]);

    // SmartGuide dialog using the same pattern as RuleCard
    const handleBotModelUpdate = useCallback(async (uuid: string, provider: string, model: string) => {
        const response = await api.updateImbotSetting(uuid, {
            smartguide_provider: provider,
            smartguide_model: model,
        });

        if (response.success) {
            showNotification('Bot model configuration updated', 'success');
            await loadBotSettings();
        } else {
            showNotification(response.error || 'Failed to update bot configuration', 'error');
            throw new Error(response.error || 'Failed to update bot configuration');
        }
    }, [loadBotSettings, showNotification]);

    const {
        openDialog: openBotModelDialog,
        closeDialog: closeBotModelDialog,
        BotModelDialog,
        isOpen: BotModelDialogOpen,
    } = useBotModelDialog({
        bot: selectedBot,
        providers,
        onUpdate: handleBotModelUpdate,
        onClose: () => setSelectedBot(null),
    });

    const handleBotModelSelect = useCallback((botUuid: string) => {
        const bot = bots.find(b => b.uuid === botUuid);
        if (bot) {
            setSelectedBot(bot);
            openBotModelDialog();
        }
    }, [bots, openBotModelDialog]);

    return (
        <PageLayout loading={false}>
            {/* Preview Notice Card */}
            <UnifiedCard
                title="Preview Version"
                size="full"
                sx={{ mb: 2 }}
            >
                <Alert severity="info" sx={{ mb: 2 }}>
                    <Typography variant="body2">
                        This feature is currently in <strong>preview</strong>. It is designed to work with{' '}
                        <strong>Claude Code</strong> installed on your local machine with your config.
                    </Typography>
                </Alert>
                <Typography variant="body2" color="text.secondary">
                    The <strong>Remote Control</strong> Bot enables you to interact with <strong>Claude
                    Code</strong> through instant messaging platforms
                    like Telegram.
                </Typography>
                <Typography variant="body2" color="text.secondary">
                    Make sure you have <strong>Claude Code CLI</strong> installed and configured before using this
                    feature.
                </Typography>
                <Typography variant="body2" color="text.secondary">
                    <strong>Once you enable a bot, the remote control is started with corresponding IM, and vice
                        versa.</strong>
                </Typography>
            </UnifiedCard>

            <UnifiedCard
                title="Bots"
                subtitle={`${bots.length} bot${bots.length !== 1 ? 's' : ''} configured`}
                size="full"
                sx={{ mb: 2 }}
                rightAction={
                    <Button
                        variant="contained"
                        startIcon={<Add />}
                        onClick={() => handleOpenBotTokenDialog()}
                        size="small"
                    >
                        Add Bot
                    </Button>
                }
            >
                {botLoading ? (
                    <Box sx={{ display: 'flex', justifyContent: 'center', py: 4 }}>
                        <CircularProgress />
                    </Box>
                ) : bots.length === 0 ? (
                    <EmptyStateGuide
                        title="No Bots Configured"
                        description="Configure bots to enable remote-control chat integration."
                        showOAuthButton={false}
                        showHeroIcon={false}
                        primaryButtonLabel="Add Bot"
                        onAddApiKeyClick={() => handleOpenBotTokenDialog()}
                    />
                ) : (
                    bots.map((bot) => (
                        <div key={bot.uuid}>
                            <BotCard
                                bot={bot}
                                providers={providers}
                                onEdit={() => handleOpenBotTokenDialog(bot.uuid)}
                                onDelete={() => handleDeleteBot(bot.uuid!)}
                                onBotToggle={() => handleBotToggle(bot.uuid!, !bot.enabled)}
                                onRestart={() => handleBotRestart(bot.uuid!)}
                                onModelClick={() => handleBotModelSelect(bot.uuid!)}
                                onCWDChange={(cwd) => handleCWDChange(bot.uuid!, cwd)}
                                isToggling={togglingBotUuid === bot.uuid}
                                isRestarting={restartingBotUuid === bot.uuid}
                            />
                        </div>
                    ))
                )}
            </UnifiedCard>

            {/* Bot Add/Edit Dialog */}
            <Modal open={botTokenDialogOpen} onClose={(e, reason) => {
                // Don't allow closing when in QR binding mode - user must complete or cancel
                if (botDialogMode !== 'qr-binding') {
                    setBotTokenDialogOpen(false);
                }
            }}>
                <Stack
                    sx={{
                        position: 'absolute',
                        top: '50%',
                        left: '50%',
                        transform: 'translate(-50%, -50%)',
                        width: 600,
                        maxWidth: '80vw',
                        maxHeight: '80vh',
                        overflowY: 'auto',
                        bgcolor: 'background.paper',
                        boxShadow: 24,
                        p: 4,
                        borderRadius: 2,
                        gap: 2,
                    }}
                >
                    <Typography
                        variant="h6">
                        {botDialogMode === 'edit' ? 'Edit Bot Configuration' :
                         botDialogMode === 'qr-binding' ? 'Scan QR Code to Bind' :
                         'Add Bot Configuration'}
                    </Typography>
                    <Stack spacing={2}>
                        {/* In QR binding mode, only show the QR auth form, hide other fields */}
                        {botDialogMode !== 'qr-binding' && (
                            <>
                        <Stack spacing={1}>
                            <Typography variant="body2" color="text.secondary">
                                Platform
                            </Typography>
                            <BotPlatformSelector
                                value={botPlatformDraft}
                                onChange={(platform) => {
                                    setBotPlatformDraft(platform);
                                    // Clear auth draft when platform changes
                                    setBotAuthDraft({});
                                    // Track platform default for require_pairing
                                    // unless the operator has manually overridden.
                                    if (!botRequirePairingTouched) {
                                        setBotRequirePairingDraft(platformDefaultRequirePairing(platform));
                                    }
                                    // Update current platform config
                                    const config = botPlatforms.find(p => p.platform === platform);
                                    if (config) {
                                        setCurrentPlatformConfig(config);
                                    }
                                }}
                                platforms={botPlatforms}
                                loading={botPlatformsLoading}
                                disabled={botSaving}
                            />
                        </Stack>

                        {currentPlatformConfig && (
                            <BotAuthForm
                                platform={botPlatformDraft}
                                authType={currentPlatformConfig.auth_type}
                                fields={currentPlatformConfig.fields}
                                authData={botAuthDraft}
                                onChange={(key, value) => setBotAuthDraft(prev => ({ ...prev, [key]: value }))}
                                disabled={botSaving}
                                botUUID={botDialogMode === 'qr-binding' ? botEditUuid : undefined}
                                onBindingComplete={botDialogMode === 'qr-binding' ? handleQRBindingComplete : undefined}
                            />
                        )}

                        <Box>
                            <FormControlLabel
                                control={
                                    <Switch
                                        checked={botRequirePairingDraft}
                                        onChange={(e) => {
                                            setBotRequirePairingDraft(e.target.checked);
                                            setBotRequirePairingTouched(true);
                                        }}
                                        disabled={botSaving}
                                    />
                                }
                                label="Require TOFU pairing"
                            />
                            <FormHelperText>
                                {platformDefaultRequirePairing(botPlatformDraft)
                                    ? 'Recommended — anyone with the bot token can otherwise DM and run commands. After save, the bot card will show a one-time pairing code; DM the bot with /bind <code> to bind your chat.'
                                    : 'Optional — adds a /bind <code> handshake before the bot accepts commands.'}
                            </FormHelperText>
                        </Box>

                        <TextField
                            label="Alias"
                            placeholder="My Bot"
                            value={botNameDraft}
                            onChange={(e) => setBotNameDraft(e.target.value)}
                            fullWidth
                            size="small"
                            helperText="Optional: a friendly name for this bot configuration."
                            disabled={botSaving}
                        />

                        <TextField
                            label="Proxy URL"
                            placeholder="http://user:pass@host:port"
                            value={botProxyDraft}
                            onChange={(e) => setBotProxyDraft(e.target.value)}
                            fullWidth
                            size="small"
                            helperText="Optional HTTP/HTTPS proxy for bot API requests."
                            disabled={botSaving}
                        />

                        <TextField
                            label="Chat ID Lock"
                            placeholder="e.g. 123456789"
                            value={botChatIdDraft}
                            onChange={(e) => setBotChatIdDraft(e.target.value)}
                            fullWidth
                            size="small"
                            helperText="Optional: when set, only this chat ID can use the bot."
                            disabled={botSaving}
                        />

                        <TextField
                            label="Bash Allowlist"
                            placeholder="cd\nls\npwd"
                            value={botAllowlistDraft}
                            onChange={(e) => setBotAllowlistDraft(e.target.value)}
                            fullWidth
                            multiline
                            minRows={3}
                            size="small"
                            helperText="Allowlisted /bash subcommands. Default: cd, ls, pwd."
                            disabled={botSaving}
                        />
                            </>
                        )}

                        {/* In QR binding mode, show only the QR auth form */}
                        {botDialogMode === 'qr-binding' && currentPlatformConfig && (
                            <BotAuthForm
                                platform={botPlatformDraft}
                                authType={currentPlatformConfig.auth_type}
                                fields={currentPlatformConfig.fields}
                                authData={botAuthDraft}
                                onChange={(key, value) => setBotAuthDraft(prev => ({ ...prev, [key]: value }))}
                                disabled={botSaving}
                                botUUID={botEditUuid || undefined}
                                onBindingComplete={handleQRBindingComplete}
                            />
                        )}
                    </Stack>

                    <Stack direction="row" spacing={2} justifyContent="flex-end">
                        {botDialogMode === 'qr-binding' ? (
                            <Button
                                onClick={() => {
                                    // Delete the incomplete bot and close
                                    if (botEditUuid) {
                                        api.deleteImBotSetting(botEditUuid);
                                    }
                                    setBotTokenDialogOpen(false);
                                }}
                                color="error"
                            >
                                Cancel Binding
                            </Button>
                        ) : (
                            <>
                                <Button
                                    onClick={() => setBotTokenDialogOpen(false)}
                                    color="inherit"
                                    disabled={botSaving}
                                >
                                    Cancel
                                </Button>
                                <Button
                                    variant="contained"
                                    onClick={handleSaveBotToken}
                                    disabled={botSaving || botLoading}
                                >
                                    {botSaving ? 'Saving...' : 'Save Configuration'}
                                </Button>
                            </>
                        )}
                    </Stack>
                </Stack>
            </Modal>

            {/* SmartGuide Selector Dialog */}
            <BotModelDialog open={BotModelDialogOpen} />

            {/* Snackbar for notifications */}
            <Snackbar
                open={snackbar.open}
                autoHideDuration={snackbar.severity === 'error' ? null : 4000}
                onClose={() => setSnackbar(prev => ({ ...prev, open: false }))}
                anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
            >
                <Alert
                    onClose={() => setSnackbar(prev => ({ ...prev, open: false }))}
                    severity={snackbar.severity}
                    sx={{ width: '100%' }}
                >
                    {snackbar.message}
                </Alert>
            </Snackbar>
        </PageLayout>
    );
};

export default BotPage;
