import { Injectable, NotFoundException, ForbiddenException, BadRequestException } from '@nestjs/common';
import * as XLSX from 'xlsx';
import { UserService } from '../user/user.service';
import { TenantService } from '../tenant/tenant.service';
import { I18nService } from '../i18n/i18n.service';

@Injectable()
export class AdminService {
    constructor(
        private readonly userService: UserService,
        private readonly tenantService: TenantService,
        private readonly i18nService: I18nService,
    ) { }

    async getTenantUsers(tenantId?: string, page?: number, limit?: number) {
        if (!tenantId) {
            return this.userService.findAll(page, limit);
        }
        return this.userService.findByTenantId(tenantId, page, limit);
    }

    async exportUsers(tenantId?: string): Promise<Buffer> {
        const { data: users } = tenantId 
            ? await this.userService.findByTenantId(tenantId)
            : await this.userService.findAll();
        
        const worksheet = XLSX.utils.json_to_sheet(users.map(u => ({
            Username: u.username,
            DisplayName: u.displayName || '',
            IsAdmin: u.isAdmin ? 'Yes' : 'No',
            CreatedAt: u.createdAt,
            Password: '', // Placeholder for new users
        })));

        const workbook = XLSX.utils.book_new();
        XLSX.utils.book_append_sheet(workbook, worksheet, 'Users');

        return XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' });
    }

    async importUsers(tenantId?: string, file?: any) {
        if (!file) throw new BadRequestException(this.i18nService.getMessage('uploadNoFile'));

        const workbook = XLSX.read(file.buffer, { type: 'buffer' });
        const sheetName = workbook.SheetNames[0];
        const worksheet = workbook.Sheets[sheetName];
        const data = XLSX.utils.sheet_to_json(worksheet) as any[];

        const results = {
            success: 0,
            failed: 0,
            errors: [] as string[],
        };

        for (const row of data) {
            try {
                const username = (row.Username || row.username)?.toString();
                const displayName = (row.DisplayName || row.displayName || row.Name || row.name)?.toString();
                const password = (row.Password || row.password)?.toString();
                const isAdminStr = (row.IsAdmin || row.isAdmin || 'No').toString();
                const isAdmin = isAdminStr.toLowerCase() === 'yes' || isAdminStr === 'true' || isAdminStr === '1';

                if (!username) {
                    throw new Error(this.i18nService.getMessage('usernameRequired'));
                }

                const existingUser = await this.userService.findOneByUsername(username);

                if (existingUser) {
                    await this.userService.updateUser(existingUser.id, {
                        displayName: displayName || existingUser.displayName,
                        password: password || undefined,
                        // We avoid changing isAdmin status via import for security unless explicitly required
                    });
                } else {
                    if (!password) {
                        throw new Error(this.i18nService.formatMessage('passwordRequiredForNewUser', { username }));
                    }
                    await this.userService.createUser(
                        username,
                        password,
                        isAdmin,
                        tenantId,
                        displayName
                    );
                }
                results.success++;
            } catch (e: any) {
                results.failed++;
                results.errors.push(`${row.Username || 'Unknown'}: ${e.message}`);
            }
        }

        return results;
    }

    async getTenantSettings(tenantId: string) {
        const targetTenantId = tenantId || await this.tenantService.getSystemTenantId();
        return this.tenantService.getSettings(targetTenantId);
    }

    async updateTenantSettings(tenantId: string, data: any) {
        const targetTenantId = tenantId || await this.tenantService.getSystemTenantId();
        return this.tenantService.updateSettings(targetTenantId, data);
    }

    // Notebook sharing approval and model assignments would go here
    async getPendingShares(tenantId: string) {
        // Mock implementation for pending shares to satisfy UI.
        // Needs proper schema/entity support in the future.
        return [];
    }
}
