/**
 * User Service
 * Handles all user-related database operations including sessions, teams, and profiles
 */

import { BaseService } from './BaseService';
import * as schema from '../schema';
import { eq, and, sql, lt, ne } from 'drizzle-orm';
import { generateId } from '../../utils/idGenerator';

/**
 * User Service Class
 */
export class UserService extends BaseService {

    // ========================================
    // USER MANAGEMENT
    // ========================================

    async createUser(userData: schema.NewUser): Promise<schema.User> {
        const [user] = await this.database
            .insert(schema.users)
            .values({ ...userData, id: generateId() })
            .returning();
        return user;
    }

    /**
     * User lookup method
     */
    async findUser(options: {
        id?: string;
        email?: string;
        provider?: { name: string; id: string };
    }): Promise<schema.User | null> {
        const whereConditions = [
            options.id ? eq(schema.users.id, options.id) : undefined,
            options.email ? eq(schema.users.email, options.email) : undefined,
            options.provider ? and(
                eq(schema.users.provider, options.provider.name),
                eq(schema.users.providerId, options.provider.id)
            ) : undefined
        ].filter(Boolean); // Remove undefined values
        
        if (whereConditions.length === 0) {
            return null;
        }
        
        const users = await this.database
            .select()
            .from(schema.users)
            .where(whereConditions.length === 1 ? whereConditions[0] : and(...whereConditions))
            .limit(1);
            
        return users[0] || null;
    }

    async updateUserActivity(userId: string): Promise<void> {
        await this.database
            .update(schema.users)
            .set({ 
                lastActiveAt: new Date(),
                updatedAt: new Date()
            })
            .where(eq(schema.users.id, userId));
    }

    // ========================================
    // SESSION MANAGEMENT
    // ========================================

    async createSession(sessionData: schema.NewSession): Promise<schema.Session> {
        const [session] = await this.database
            .insert(schema.sessions)
            .values({ ...sessionData, id: generateId() })
            .returning();
        return session;
    }

    async findValidSession(sessionId: string): Promise<schema.Session | null> {
        const sessions = await this.database
            .select()
            .from(schema.sessions)
            .where(and(
                eq(schema.sessions.id, sessionId),
                sql`${schema.sessions.expiresAt} > CURRENT_TIMESTAMP`
            ))
            .limit(1);
        return sessions[0] || null;
    }

    async cleanupExpiredSessions(): Promise<void> {
        const now = new Date();
        await this.database
            .delete(schema.sessions)
            .where(lt(schema.sessions.expiresAt, now));
    }

    // ========================================
    // USER PROFILE OPERATIONS
    // ========================================

    /**
     * Update user profile directly
     */
    async updateUserProfile(
        userId: string,
        profileData: {
            displayName?: string;
            username?: string;
            bio?: string;
            avatarUrl?: string;
            timezone?: string;
        }
    ): Promise<void> {
        await this.database
            .update(schema.users)
            .set({
                ...profileData,
                updatedAt: new Date()
            })
            .where(eq(schema.users.id, userId));
    }

    /**
     * Resolve whether the user's own Cloudflare AI Gateway should be used for inference.
     *
     * The stored column is nullable; null means "use the derived default", which is OFF
     * for users who signed in with Cloudflare (gateway auto-connected without explicit
     * opt-in) and ON for everyone else (who connected the gateway deliberately).
     *
     * Returns `enabled` (the effective value) and `isExplicit` (whether the user has set
     * the preference, vs. falling back to the default) so callers/UI can distinguish.
     */
    async getAiGatewayPreference(userId: string): Promise<{ enabled: boolean; isExplicit: boolean }> {
        const row = await this.database
            .select({ provider: schema.users.provider, aiGatewayEnabled: schema.users.aiGatewayEnabled })
            .from(schema.users)
            .where(eq(schema.users.id, userId))
            .get();

        if (!row) {
            return { enabled: false, isExplicit: false };
        }
        if (row.aiGatewayEnabled === null) {
            return { enabled: row.provider !== 'cloudflare', isExplicit: false };
        }
        return { enabled: row.aiGatewayEnabled, isExplicit: true };
    }

    /**
     * Persist the user's explicit AI Gateway usage preference.
     */
    async setAiGatewayPreference(userId: string, enabled: boolean): Promise<void> {
        await this.database
            .update(schema.users)
            .set({ aiGatewayEnabled: enabled, updatedAt: new Date() })
            .where(eq(schema.users.id, userId));
    }

    /**
     * Check if username is available
     */
    async isUsernameAvailable(username: string, excludeUserId?: string): Promise<boolean> {
        const existingUser = await this.database
            .select({ id: schema.users.id })
            .from(schema.users)
            .where(
                and(
                    eq(schema.users.username, username),
                    excludeUserId ? ne(schema.users.id, excludeUserId) : undefined
                )
            )
            .get();
        
        return !existingUser;
    }

    /**
     * Update user profile with comprehensive validation
     */
    async updateUserProfileWithValidation(
        userId: string,
        profileData: {
            username?: string;
            displayName?: string;
            bio?: string;
            theme?: 'light' | 'dark' | 'system';
        }
    ): Promise<{ success: boolean; message: string }> {
        // Validate username if provided
        if (profileData.username) {
            const { username } = profileData;

            // Format validation
            if (!/^[a-zA-Z0-9_-]+$/.test(username)) {
                return { 
                    success: false, 
                    message: 'Username can only contain letters, numbers, underscores, and hyphens' 
                };
            }
            
            if (username.length < 3 || username.length > 30) {
                return { 
                    success: false, 
                    message: 'Username must be between 3 and 30 characters' 
                };
            }
            
            // Check reserved usernames
            const reserved = ['admin', 'api', 'www', 'mail', 'ftp', 'root', 'support', 'help', 'about', 'terms', 'privacy'];
            if (reserved.includes(username.toLowerCase())) {
                return { 
                    success: false, 
                    message: 'Username is reserved' 
                };
            }
            
            // Check uniqueness
            const existingUser = await this.database
                .select({ id: schema.users.id })
                .from(schema.users)
                .where(eq(schema.users.username, username))
                .get();

            if (existingUser && existingUser.id !== userId) {
                return { 
                    success: false, 
                    message: 'Username already taken' 
                };
            }
        }

        // Update profile
        await this.database
            .update(schema.users)
            .set({
                username: profileData.username || undefined,
                displayName: profileData.displayName || undefined,
                bio: profileData.bio || undefined,
                theme: profileData.theme || undefined,
                updatedAt: new Date()
            })
            .where(eq(schema.users.id, userId));

        return { success: true, message: 'Profile updated successfully' };
    }

    /**
     * Get basic user statistics efficiently
     */
    async getUserStatisticsBasic(userId: string): Promise<{ totalApps: number; appsThisMonth: number }> {
        const startOfMonth = new Date();
        startOfMonth.setDate(1);
        startOfMonth.setHours(0, 0, 0, 0);

        const [totalApps, appsThisMonth] = await Promise.all([
            // Total apps count
            this.database
                .select({ count: sql<number>`COUNT(*)` })
                .from(schema.apps)
                .where(eq(schema.apps.userId, userId))
                .get()
                .then(r => Number(r?.count) || 0),

            // Apps created this month
            this.database
                .select({ count: sql<number>`COUNT(*)` })
                .from(schema.apps)
                .where(and(
                    eq(schema.apps.userId, userId),
                    sql`${schema.apps.createdAt} >= ${startOfMonth}`
                ))
                .get()
                .then(r => Number(r?.count) || 0)
        ]);

        return { totalApps, appsThisMonth };
    }

}