import prisma from '../lib/prisma';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import fs from 'fs';
import path from 'path';
import dotenv from 'dotenv';

const JWT_SECRET = process.env.JWT_SECRET || 'secret';

export class AuthService {
    static async getUser(userId: string) {
        const user = await prisma.user.findUnique({
            where: { id: userId },
            include: { profile: true }
        });

        if (!user) return null;

        const { password: _, ...userSafe } = user;
        return userSafe;
    }

    static async login(email: string, password: string) {
        const user = await prisma.user.findUnique({
            where: { email },
            include: { profile: true }
        });

        if (!user) {
            throw new Error('Invalid credentials');
        }

        if (user.isBlocked) {
            throw new Error('Account is blocked');
        }

        const isMatch = await bcrypt.compare(password, user.password);
        if (!isMatch) {
            throw new Error('Invalid credentials');
        }

        const token = jwt.sign({ userId: user.id, role: user.role }, JWT_SECRET);
        const { password: _, ...userSafe } = user;

        return { user: userSafe, token };
    }

    static async register(email: string, password: string) {
        const existingUser = await prisma.user.findUnique({ where: { email } });
        if (existingUser) {
            throw new Error('User already exists');
        }

        const hashedPassword = await bcrypt.hash(password, 10);

        const user = await prisma.user.create({
            data: {
                email,
                password: hashedPassword,
                role: 'USER',
                profile: {
                    create: {
                        weight: 70
                    }
                }
            },
            include: { profile: true }
        });

        const token = jwt.sign({ userId: user.id, role: user.role }, JWT_SECRET);
        const { password: _, ...userSafe } = user;

        return { user: userSafe, token };
    }

    static async seedDefaultExercises(userId: string, language: string = 'en') {
        try {
            // Ensure env is loaded from root (in case server didn't restart)
            if (!process.env.DEFAULT_EXERCISES_CSV_PATH) {
                const rootEnv = path.resolve(process.cwd(), '../.env');
                if (fs.existsSync(rootEnv)) {
                    dotenv.config({ path: rootEnv, override: true });
                } else {
                    dotenv.config({ path: path.resolve(process.cwd(), '.env'), override: true });
                }
            }

            const csvPath = process.env.DEFAULT_EXERCISES_CSV_PATH;

            if (csvPath) {
                let resolvedPath = path.resolve(process.cwd(), csvPath);

                // Try to handle if resolvedPath doesn't exist but relative to root does (if CWD is server)
                if (!fs.existsSync(resolvedPath) && !path.isAbsolute(csvPath)) {
                    const altPath = path.resolve(process.cwd(), '..', csvPath);
                    if (fs.existsSync(altPath)) {
                        resolvedPath = altPath;
                    }
                }

                if (fs.existsSync(resolvedPath)) {
                    const content = fs.readFileSync(resolvedPath, 'utf-8');
                    const lines = content.split(/\r?\n/).filter(l => l.trim().length > 0);

                    if (lines.length > 1) {
                        const headers = lines[0].split(',').map(h => h.trim());
                        const exercisesToCreate = [];

                        const nameColumn = language === 'ru' ? 'name_ru' : 'name';

                        for (let i = 1; i < lines.length; i++) {
                            const cols = lines[i].split(',').map(c => c.trim());
                            if (cols.length < headers.length) continue;

                            const row: any = {};
                            headers.forEach((h, idx) => row[h] = cols[idx]);

                            const exerciseName = row[nameColumn] || row['name'];

                            if (exerciseName && row.type) {
                                exercisesToCreate.push({
                                    userId,
                                    name: exerciseName,
                                    type: row.type,
                                    bodyWeightPercentage: row.bodyWeightPercentage ? parseFloat(row.bodyWeightPercentage) : 0,
                                    isUnilateral: row.isUnilateral === 'true',
                                    isArchived: false
                                });
                            }
                        }

                        if (exercisesToCreate.length > 0) {
                            // Check if exercises already exist for this user to avoid duplicates
                            const existingCount = await prisma.exercise.count({ where: { userId } });
                            if (existingCount === 0) {
                                await prisma.exercise.createMany({
                                    data: exercisesToCreate
                                });
                                console.log(`[AuthService] Seeded ${exercisesToCreate.length} exercises for user: ${userId}`);
                            } else {
                                console.log(`[AuthService] User ${userId} already has ${existingCount} exercises. Skipping seed.`);
                            }
                        }
                    }
                } else {
                    console.warn(`[AuthService] Default exercises CSV configured but not found at: ${resolvedPath}`);
                }
            }
        } catch (error) {
            try { fs.appendFileSync(path.join(process.cwd(), 'auth_debug_custom.log'), `[${new Date().toISOString()}] ERROR: ${error}\n`); } catch (e) { }
            console.error('[AuthService] Failed to seed default exercises:', error);
            // Non-blocking error
        }
    }

    static async initializeUser(userId: string, language: string, profileData: any = {}) {
        // Prepare profile update data
        const updateData: any = { language };

        if (profileData.weight && !isNaN(parseFloat(profileData.weight))) updateData.weight = parseFloat(profileData.weight);
        if (profileData.height && !isNaN(parseFloat(profileData.height))) updateData.height = parseFloat(profileData.height);
        if (profileData.gender) updateData.gender = profileData.gender;
        if (profileData.birthDate && profileData.birthDate !== '') {
            const date = new Date(profileData.birthDate);
            if (!isNaN(date.getTime())) {
                updateData.birthDate = date;
            }
        }

        // Update profile language and other attributes
        await prisma.userProfile.upsert({
            where: { userId },
            update: updateData,
            create: { userId, ...updateData }
        });

        // Seed exercises in that language
        await this.seedDefaultExercises(userId, language);

        // Mark as first login done
        await prisma.user.update({
            where: { id: userId },
            data: { isFirstLogin: false }
        });

        // Return updated user
        return this.getUser(userId);
    }

    static async changePassword(userId: string, newPassword: string) {
        const hashed = await bcrypt.hash(newPassword, 10);

        await prisma.user.update({
            where: { id: userId },
            data: {
                password: hashed
            }
        });
    }

    static async updateProfile(userId: string, data: any) {
        // Convert birthDate if needed
        if (data.birthDate) {
            data.birthDate = new Date(data.birthDate);
        }

        await prisma.userProfile.upsert({
            where: { userId: userId },
            update: { ...data },
            create: { userId: userId, ...data }
        });
    }

    static async getAllUsers() {
        const users = await prisma.user.findMany({
            select: {
                id: true,
                email: true,
                role: true,
                isBlocked: true,
                isFirstLogin: true,
                profile: true
            },
            orderBy: {
                email: 'asc'
            }
        });
        return users;
    }

    static async deleteUser(adminId: string, targetId: string) {
        if (targetId === adminId) {
            throw new Error('Cannot delete yourself');
        }
        await prisma.user.delete({ where: { id: targetId } });
    }

    static async blockUser(adminId: string, targetId: string, block: boolean) {
        if (targetId === adminId) {
            throw new Error('Cannot block yourself');
        }
        await prisma.user.update({
            where: { id: targetId },
            data: { isBlocked: block }
        });
    }

    static async resetUserPassword(targetId: string, newPassword: string) {
        if (!newPassword || newPassword.length < 4) {
            throw new Error('Password too short');
        }

        const hashed = await bcrypt.hash(newPassword, 10);

        await prisma.user.update({
            where: { id: targetId },
            data: {
                password: hashed,
                isFirstLogin: true
            }
        });
    }
}
