/**
 * 🔐 VIGTHORIA AUTHENTICATION SERVICE
 * 
 * Connects to Vigthoria Coder Web Service for user authentication
 * and subscription verification.
 * 
 * Features:
 * - OAuth-style authentication with Vigthoria Coder
 * - Subscription tier verification
 * - Feature gating based on subscription
 * - Auto-refresh tokens
 * - Login/Logout flow
 * 
 * @author Vigthoria Security Team
 * @version 2.0.1
 * @since 2026-01-12
 */

const vscode = require('vscode');
const crypto = require('crypto');

// Canonical tier names for the Vigthoria Coder product.
// ALL other plan name variants must map to one of these:
//   community | developer | professional | enterprise | admin | master_admin
function normalizeSubscriptionTier(tier) {
    const normalized = (tier || '').toLowerCase().trim();
    const aliases = {
        // Community / free-profile (authenticated but no paid Coder features)
        'free':         'community',
        'community':    'community',
        // Coder paid tiers
        'basic':        'developer',
        'dev':          'developer',
        'developer':    'developer',
        'pro':          'professional',
        'professional': 'professional',
        'premium':      'professional',
        'enterprise':   'enterprise',
        // Admin roles bypass all feature gates
        'admin':        'admin',
        'master_admin': 'master_admin',
    };
    // Default to 'community' – never fall back to a paid tier for unknown plans
    return aliases[normalized] ?? 'community';
};


function isAcceptedUserToken(token) {
    if (!token || typeof token !== 'string') {
        return false;
    }

    if (/^(vgt_|ent_|dev_|pro_|adm_|mast_)/.test(token)) {
        return token.length >= 32;
    }

    return /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/.test(token);
}

// Canonical Vigthoria Coder subscription tiers.
// 'community' = free Vigthoria account (auth allowed, zero paid Coder features)
// Paid tiers: developer ($29) → professional ($79) → enterprise ($199)
const SUBSCRIPTION_TIERS = {
    community: {
        name: 'Community (Free)',
        features: [],          // No Coder features — show paywall
        requiredUpgrade: 'developer',
        limits: {
            dailyRequests: 0,
            maxFileSize: 0,
            agents: 0,
            modes: []          // No Coder modes — show upgrade prompt
        }
    },
    developer: {
        name: 'Developer ($29/mo)',
        features: ['ask-mode', 'build-mode', 'auto-mode', 'basic-chat', 'code-analysis'],
        limits: {
            dailyRequests: 100,
            maxFileSize: 1024 * 500,    // 500 KB
            agents: 1,
            modes: ['ask', 'build', 'auto', 'chat', 'assistant']
        }
    },
    professional: {
        name: 'Professional ($79/mo)',
        features: ['ask-mode', 'build-mode', 'auto-mode', 'agent-mode',
                   'live-preview', 'code-dna', 'predictive-debug',
                   'code-review', 'ai-personality', 'basic-chat', 'code-analysis'],
        limits: {
            dailyRequests: 1000,
            maxFileSize: 1024 * 1024 * 5,   // 5 MB
            agents: 10,
            modes: ['ask', 'build', 'auto', 'agent', 'chat', 'assistant', 'developer']
        }
    },
    enterprise: {
        name: 'Enterprise ($199/mo)',
        features: ['all'],
        limits: {
            dailyRequests: -1,              // Unlimited
            maxFileSize: 1024 * 1024 * 50,  // 50 MB
            agents: -1,                     // Unlimited
            modes: ['ask', 'build', 'auto', 'agent', 'operator',
                    'chat', 'assistant', 'developer', 'autonomous', 'custom']
        }
    },
    admin: {
        name: 'Admin',
        features: ['all'],
        limits: {
            dailyRequests: -1,
            maxFileSize: 1024 * 1024 * 50,
            agents: -1,
            modes: ['ask', 'build', 'auto', 'agent', 'operator',
                    'chat', 'assistant', 'developer', 'autonomous', 'custom', 'admin']
        }
    },
    master_admin: {
        name: 'Master Admin',
        features: ['all'],
        limits: {
            dailyRequests: -1,
            maxFileSize: 1024 * 1024 * 50,
            agents: -1,
            modes: ['ask', 'build', 'auto', 'agent', 'operator',
                    'chat', 'assistant', 'developer', 'autonomous', 'custom', 'admin']
        }
    }
};

class VigthoriaAuthService {
    constructor(context) {
        this.context = context;
        this.secretStorage = context.secrets;
        
        // Authentication endpoints
        this.authConfig = {
            baseUrl: 'https://coder.vigthoria.io',
            authEndpoint: '/api/auth/verify',
            loginEndpoint: '/api/auth/login',
            refreshEndpoint: '/api/auth/refresh',
            subscriptionEndpoint: '/api/subscription/status',
            
            // Fallback for local development
            fallbackUrl: 'https://coder.vigthoria.io',
            
            // Storage keys
            accessTokenKey: 'vigthoria.accessToken',
            refreshTokenKey: 'vigthoria.refreshToken',
            userDataKey: 'vigthoria.userData',
            subscriptionKey: 'vigthoria.subscription',
            lastVerifyKey: 'vigthoria.lastVerify'
        };
        
        this.isAuthenticated = false;
        this.currentUser = null;
        this.currentSubscription = null;
        this.verifyInterval = null;
    }

    /**
     * Initialize authentication service
     */
    async initialize() {
        console.log('🔐 Initializing Vigthoria Auth Service...');
        
        try {
            // Check for existing session
            const existingToken = await this.getAccessToken();
            
            if (existingToken) {
                // First, try to load cached user data immediately (for fast startup)
                await this.loadUserData();
                const lastVerify = this.context.globalState.get(this.authConfig.lastVerifyKey);
                
                // If we have cached data verified within the last 24 hours, use it immediately
                // and verify in background (don't block activation)
                if (this.isAuthenticated && lastVerify && (Date.now() - lastVerify) < 24 * 60 * 60 * 1000) {
                    console.log('✅ Using cached session (verified within 24h)');
                    this.startPeriodicVerification();
                    
                    // Verify in background — don't block
                    this.verifyToken(existingToken).then(valid => {
                        if (!valid) {
                            console.warn('⚠️ Background token verify failed, session may expire soon');
                        }
                    }).catch(() => {});
                    
                    return { authenticated: true, user: this.currentUser };
                }
                
                // No recent cache — verify token now
                const isValid = await this.verifyToken(existingToken);
                
                if (isValid) {
                    console.log('✅ Existing session restored');
                    await this.loadUserData();
                    this.startPeriodicVerification();
                    return { authenticated: true, user: this.currentUser };
                } else {
                    // Try to refresh
                    const refreshed = await this.refreshSession();
                    if (refreshed) {
                        return { authenticated: true, user: this.currentUser };
                    }
                    
                    // If we have cached data at all, allow it with a warning
                    if (this.isAuthenticated) {
                        console.log('⚠️ Token verify failed but using cached session');
                        this.startPeriodicVerification();
                        return { authenticated: true, user: this.currentUser };
                    }
                }
            }
            
            // No valid session, require login
            return { authenticated: false, requiresLogin: true };
            
        } catch (error) {
            console.error('❌ Auth initialization error:', error);
            
            // Even on error, try to use cached session
            await this.loadUserData();
            if (this.isAuthenticated) {
                console.log('⚠️ Auth error but using cached session');
                return { authenticated: true, user: this.currentUser };
            }
            
            return { authenticated: false, error: error.message };
        }
    }

    /**
     * Prompt user for login
     */
    async promptLogin() {
        const loginOptions = [
            {
                label: '$(sign-in) Login with Vigthoria Account',
                description: 'Sign in to access AI features',
                action: 'browser'
            },
            {
                label: '$(key) Enter API Token',
                description: 'Use existing API token',
                action: 'token'
            },
            {
                label: '$(info) Create Account',
                description: 'Sign up for Vigthoria Coder',
                action: 'signup'
            }
        ];

        const selection = await vscode.window.showQuickPick(loginOptions, {
            placeHolder: '🔐 Login to Vigthoria Coder to continue',
            title: 'Vigthoria Authentication Required'
        });

        if (!selection) {
            return { authenticated: false, cancelled: true };
        }

        switch (selection.action) {
            case 'browser':
                return await this.loginWithBrowser();
            case 'token':
                return await this.loginWithToken();
            case 'signup':
                return await this.openSignup();
            default:
                return { authenticated: false };
        }
    }

    /**
     * Login via browser OAuth flow
     */
    async loginWithBrowser() {
        try {
            // Generate state for CSRF protection
            const state = crypto.randomBytes(32).toString('hex');
            await this.secretStorage.store('vigthoria.authState', state);
            
            // Open browser for login
            const loginUrl = `${this.authConfig.baseUrl}/auth/vscode?state=${state}&redirect=vscode://vigthoria.vigthoria-ai-chat/callback`;
            
            await vscode.env.openExternal(vscode.Uri.parse(loginUrl));
            
            // Show waiting message
            const result = await vscode.window.showInputBox({
                prompt: 'After logging in, paste the verification code here',
                placeHolder: 'Verification code from browser...',
                password: true,
                title: '🔐 Enter Verification Code'
            });

            if (!result) {
                return { authenticated: false, cancelled: true };
            }

            // Verify the code
            return await this.verifyAuthCode(result);
            
        } catch (error) {
            console.error('Browser login failed:', error);
            vscode.window.showErrorMessage(`Login failed: ${error.message}`);
            return { authenticated: false, error: error.message };
        }
    }

    /**
     * Login with API token
     */
    async loginWithToken() {
        const token = await vscode.window.showInputBox({
            prompt: 'Enter your Vigthoria API token',
            placeHolder: 'vgt_xxx, pro_xxx, ent_xxx, or JWT token',
            password: true,
            title: '🔐 Vigthoria API Token',
            validateInput: (value) => {
                if (!value) return 'Token is required';
                if (!isAcceptedUserToken(value)) {
                    return 'Invalid token format. Use a Vigthoria API token or JWT access token.';
                }
                return null;
            }
        });

        if (!token) {
            return { authenticated: false, cancelled: true };
        }

        try {
            // Verify token with server
            const verified = await this.verifyToken(token);
            
            if (verified) {
                await this.secretStorage.store(this.authConfig.accessTokenKey, token);
                await this.loadSubscription();
                this.startPeriodicVerification();
                
                vscode.window.showInformationMessage(
                    `✅ Logged in as ${this.currentUser?.email || 'Vigthoria User'} (${this.currentSubscription?.tier || 'basic'})`
                );
                
                return { authenticated: true, user: this.currentUser };
            } else {
                vscode.window.showErrorMessage('❌ Invalid token. Please check and try again.');
                return { authenticated: false, error: 'Invalid token' };
            }
        } catch (error) {
            vscode.window.showErrorMessage(`❌ Authentication failed: ${error.message}`);
            return { authenticated: false, error: error.message };
        }
    }

    /**
     * Verify token with Vigthoria Coder service
     */
    async verifyToken(token) {
        try {
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), 3000); // 3s timeout for fast startup

            const response = await fetch(`${this.authConfig.baseUrl}${this.authConfig.authEndpoint}`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${token}`,
                    'X-Client': 'vigthoria-code-fork',
                    'X-Client-Version': '2.0.1'
                },
                body: JSON.stringify({ token }),
                signal: controller.signal
            });

            clearTimeout(timeoutId);

            if (response.ok) {
                const data = await response.json();
                
                this.isAuthenticated = true;
                this.currentUser = data.user;
                this.currentSubscription = data.subscription;
                
                // Store user data
                await this.context.globalState.update(this.authConfig.userDataKey, JSON.stringify(data.user));
                await this.context.globalState.update(this.authConfig.subscriptionKey, JSON.stringify(data.subscription));
                await this.context.globalState.update(this.authConfig.lastVerifyKey, Date.now());
                
                return true;
            }
            
            return false;
        } catch (error) {
            console.warn('Token verification failed:', error.message);
            
            // If network error, allow cached session for 24 hours
            const lastVerify = this.context.globalState.get(this.authConfig.lastVerifyKey);
            if (lastVerify && (Date.now() - lastVerify) < 24 * 60 * 60 * 1000) {
                console.log('Using cached session (network unavailable)');
                await this.loadUserData();
                return this.isAuthenticated;
            }
            
            return false;
        }
    }

    /**
     * Load subscription status
     */
    async loadSubscription() {
        try {
            const token = await this.getAccessToken();
            if (!token) return null;

            const response = await fetch(`${this.authConfig.baseUrl}${this.authConfig.subscriptionEndpoint}`, {
                method: 'GET',
                headers: {
                    'Authorization': `Bearer ${token}`,
                    'X-Client': 'vigthoria-code-fork'
                }
            });

            if (response.ok) {
                const data = await response.json();
                this.currentSubscription = data;
                await this.context.globalState.update(this.authConfig.subscriptionKey, JSON.stringify(data));
                return data;
            }
        } catch (error) {
            console.warn('Failed to load subscription:', error.message);
            // Use cached subscription
            const cached = this.context.globalState.get(this.authConfig.subscriptionKey);
            if (cached) {
                this.currentSubscription = JSON.parse(cached);
            }
        }
        return this.currentSubscription;
    }

        /**
     * Get the resolved subscription tier for this user.
     * Returns: community | developer | professional | enterprise | admin | master_admin
     */
    getSubscriptionTier() {
        return normalizeSubscriptionTier(this.currentSubscription?.tier || 'community');
    }

    /**
     * Returns true when user is logged in but on Community (free) plan —
     * no paid Coder access. UI should show an Upgrade / paywall prompt.
     */
    requiresUpgrade(feature) {
        if (!this.isAuthenticated) return false;
        const tier = this.getSubscriptionTier();
        if (tier === 'community') return true;
        if (feature) {
            const cfg = SUBSCRIPTION_TIERS[tier];
            return cfg && !cfg.features.includes('all') && !cfg.features.includes(feature);
        }
        return false;
    }

    /**
     * Check if user has access to a feature
     */
    hasFeature(featureName) {
        if (!this.isAuthenticated || !this.currentSubscription) {
            return false;
        }

        const tier = normalizeSubscriptionTier(this.currentSubscription.tier || 'community');
        const tierConfig = SUBSCRIPTION_TIERS[tier];

        if (!tierConfig) return false;

        // Community tier — no Coder features, show upgrade prompt
        if (tier === 'community') return false;

        // Admin / Enterprise have all features
        if (tierConfig.features.includes('all')) return true;

        return tierConfig.features.includes(featureName);
    }

    /**
     * Check if user can use a mode
     */
    canUseMode(modeName) {
        if (!this.isAuthenticated || !this.currentSubscription) {
            return false;
        }

        const tier = normalizeSubscriptionTier(this.currentSubscription.tier || 'community');
        const tierConfig = SUBSCRIPTION_TIERS[tier];

        if (!tierConfig) return false;

        // Community tier — no modes, show upgrade prompt
        if (tier === 'community') return false;

        return tierConfig.limits.modes.includes(modeName)
            || tierConfig.limits.modes.includes('custom')
            || tierConfig.limits.modes.includes('admin');
    }

    /**
     * Check rate limit - returns true if request is allowed
     */
    checkRateLimit() {
        if (!this.isAuthenticated || !this.currentSubscription) {
            return false;
        }

        const tier = normalizeSubscriptionTier(this.currentSubscription.tier || 'community');
        const tierConfig = SUBSCRIPTION_TIERS[tier];

        if (!tierConfig) return false;

        // Community tier — block all requests
        if (tier === 'community') return false;

        // Unlimited for enterprise / admin
        if (tierConfig.limits.dailyRequests === -1) {
            return true;
        }
        
        // Get daily request count
        const today = new Date().toDateString();
        const storedDate = this.context.globalState.get('vigthoria.rateLimit.date');
        let requestCount = this.context.globalState.get('vigthoria.rateLimit.count') || 0;
        
        // Reset if new day
        if (storedDate !== today) {
            requestCount = 0;
            this.context.globalState.update('vigthoria.rateLimit.date', today);
        }
        
        // Check limit
        if (requestCount >= tierConfig.limits.dailyRequests) {
            return false;
        }
        
        // Increment and save
        this.context.globalState.update('vigthoria.rateLimit.count', requestCount + 1);
        return true;
    }

    /**
     * Get subscription tier limits
     */
    getLimits() {
        const tier = normalizeSubscriptionTier(this.currentSubscription?.tier || 'community');
        return SUBSCRIPTION_TIERS[tier]?.limits || SUBSCRIPTION_TIERS.community.limits;
    }

    /**
     * Get access token
     */
    async getAccessToken() {
        return await this.secretStorage.get(this.authConfig.accessTokenKey);
    }

    /**
     * Load cached user data
     */
    async loadUserData() {
        const userData = this.context.globalState.get(this.authConfig.userDataKey);
        const subData = this.context.globalState.get(this.authConfig.subscriptionKey);
        
        if (userData) {
            this.currentUser = JSON.parse(userData);
            this.isAuthenticated = true;
        }
        
        if (subData) {
            this.currentSubscription = JSON.parse(subData);
        }
    }

    /**
     * Refresh session with refresh token
     */
    async refreshSession() {
        try {
            const refreshToken = await this.secretStorage.get(this.authConfig.refreshTokenKey);
            if (!refreshToken) return false;

            const response = await fetch(`${this.authConfig.baseUrl}${this.authConfig.refreshEndpoint}`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-Client': 'vigthoria-code-fork'
                },
                body: JSON.stringify({ refreshToken })
            });

            if (response.ok) {
                const data = await response.json();
                await this.secretStorage.store(this.authConfig.accessTokenKey, data.accessToken);
                if (data.refreshToken) {
                    await this.secretStorage.store(this.authConfig.refreshTokenKey, data.refreshToken);
                }
                await this.loadUserData();
                return true;
            }
        } catch (error) {
            console.warn('Session refresh failed:', error.message);
        }
        return false;
    }

    /**
     * Start periodic token verification
     */
    startPeriodicVerification() {
        // Verify every 30 minutes
        this.verifyInterval = setInterval(async () => {
            const token = await this.getAccessToken();
            if (token) {
                await this.verifyToken(token);
            }
        }, 30 * 60 * 1000);
    }

    /**
     * Logout user
     */
    async logout() {
        try {
            await this.secretStorage.delete(this.authConfig.accessTokenKey);
            await this.secretStorage.delete(this.authConfig.refreshTokenKey);
            await this.context.globalState.update(this.authConfig.userDataKey, undefined);
            await this.context.globalState.update(this.authConfig.subscriptionKey, undefined);
            
            this.isAuthenticated = false;
            this.currentUser = null;
            this.currentSubscription = null;
            
            if (this.verifyInterval) {
                clearInterval(this.verifyInterval);
            }
            
            vscode.window.showInformationMessage('👋 Logged out from Vigthoria');
            return true;
        } catch (error) {
            console.error('Logout error:', error);
            return false;
        }
    }

    /**
     * Open signup page
     */
    async openSignup() {
        await vscode.env.openExternal(vscode.Uri.parse(`${this.authConfig.baseUrl}/signup?source=vscode-fork`));
        return { authenticated: false, action: 'signup' };
    }

    /**
     * Verify auth code from browser
     */
    async verifyAuthCode(code) {
        try {
            const state = await this.secretStorage.get('vigthoria.authState');
            
            const response = await fetch(`${this.authConfig.baseUrl}/api/auth/callback`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ code, state })
            });

            if (response.ok) {
                const data = await response.json();
                
                await this.secretStorage.store(this.authConfig.accessTokenKey, data.accessToken);
                if (data.refreshToken) {
                    await this.secretStorage.store(this.authConfig.refreshTokenKey, data.refreshToken);
                }
                
                this.isAuthenticated = true;
                this.currentUser = data.user;
                this.currentSubscription = data.subscription;
                
                await this.context.globalState.update(this.authConfig.userDataKey, JSON.stringify(data.user));
                await this.context.globalState.update(this.authConfig.subscriptionKey, JSON.stringify(data.subscription));
                
                this.startPeriodicVerification();
                
                vscode.window.showInformationMessage(
                    `✅ Welcome, ${data.user?.name || data.user?.email}! (${data.subscription?.tier || 'basic'} tier)`
                );
                
                return { authenticated: true, user: this.currentUser };
            }
            
            return { authenticated: false, error: 'Invalid verification code' };
        } catch (error) {
            return { authenticated: false, error: error.message };
        }
    }

    /**
     * Get current subscription info for UI
     */
    getSubscriptionInfo() {
        if (!this.currentSubscription) {
            return { tier: 'community', ...SUBSCRIPTION_TIERS.community };
        }
        
        const tier = normalizeSubscriptionTier(this.currentSubscription.tier || 'community');
        return {
            ...this.currentSubscription,
            tier,
            ...SUBSCRIPTION_TIERS[tier],
            tierName: SUBSCRIPTION_TIERS[tier]?.name || 'Free'
        };
    }
}

module.exports = { VigthoriaAuthService, SUBSCRIPTION_TIERS };
