import Project from '../models/Project.js';
import Part from '../models/Part.js';
import PaintingScheme from '../models/PaintingScheme.js';
import ApplicationRecord from '../models/ApplicationRecord.js';
import Inspection from '../models/Inspection.js';

interface ProjectData {
    name: string;
    client: string;
    startDate?: string | Date;
    endDate?: string | Date;
    technician?: string;
    environment?: string;
    weightKg?: number;
}

export const createProject = async (data: ProjectData & { organizationId?: string }) => {
    const newProject = new Project({
        name: data.name,
        client: data.client,
        startDate: data.startDate ? new Date(data.startDate) : null,
        endDate: data.endDate ? new Date(data.endDate) : null,
        technician: data.technician,
        environment: data.environment,
        organizationId: data.organizationId,
        weightKg: data.weightKg
    });
    return await newProject.save();
};

export const getDashboardProjects = async (organizationId?: string) => {
    const matchStage = organizationId ? { organizationId } : {};

    const projects = await Project.aggregate([
        { $match: matchStage },
        { $sort: { name: 1 } },
        {
            $lookup: {
                from: 'paintingschemes',
                localField: '_id',
                foreignField: 'projectId',
                as: 'paintingSchemes'
            }
        },
        {
            $lookup: {
                from: 'inspections',
                localField: '_id',
                foreignField: 'projectId',
                as: 'inspections'
            }
        },
        {
            $project: {
                _id: 1,
                name: 1,
                client: 1,
                technician: 1,
                weightKg: 1,
                createdAt: 1,
                schemes: {
                    $map: {
                        input: "$paintingSchemes",
                        as: "scheme",
                        in: {
                            id: { $toString: "$$scheme._id" },
                            name: "$$scheme.name",
                            type: "$$scheme.type",
                            coat: "$$scheme.coat",
                            color: "$$scheme.color",
                            colorHex: "$$scheme.colorHex",
                            thinnerSymbol: "$$scheme.thinnerSymbol",
                            epsMin: "$$scheme.epsMin",
                            epsMax: "$$scheme.epsMax"
                        }
                    }
                },
                paintedWeight: { $sum: "$inspections.weightKg" }
            }
        }
    ]);

    return projects.map(p => ({ ...p, id: p._id.toString() }));
};

export const getAllProjects = async (organizationId?: string, isGlobalAdmin: boolean = false, status: string = 'active') => {
    const statusQuery = status === 'active'
        ? { status: { $ne: 'archived' } }
        : { status: 'archived' };

    const matchQuery: Record<string, unknown> = isGlobalAdmin
        ? { ...statusQuery }
        : {
            ...statusQuery,
            $or: [{ organizationId }, { organizationId: { $exists: false } }, { organizationId: null }]
        };

    const projects = await Project.aggregate([
        { $match: matchQuery },
        { $sort: { name: 1 } },
        {
            $lookup: {
                from: 'paintingschemes',
                localField: '_id',
                foreignField: 'projectId',
                as: 'paintingSchemes'
            }
        },
        {
            $addFields: {
                id: { $toString: "$_id" }
            }
        }
    ]);

    return projects;
};

export const archiveProject = async (id: string, organizationId?: string, isGlobalAdmin: boolean = false) => {
    const project = await Project.findById(id);
    if (!project) throw new Error('Projeto não encontrado');

    // Check ownership
    if (!isGlobalAdmin && organizationId && project.organizationId && project.organizationId !== organizationId) {
        throw new Error('Sem permissão para arquivar este projeto');
    }

    const newStatus = project.status === 'active' ? 'archived' : 'active';
    const updated = await Project.findByIdAndUpdate(id, { status: newStatus }, { new: true }).lean();
    return updated;
};

export const getProjectById = async (id: string, organizationId?: string, isGlobalAdmin: boolean = false) => {
    const project = await Project.findById(id).lean();

    if (!project) throw new Error('Projeto não encontrado');

    // Security check: Allow if global admin OR matches organization OR project has no organization
    if (!isGlobalAdmin && organizationId && project.organizationId && project.organizationId !== organizationId) {
        throw new Error('Acesso negado a este projeto');
    }

    const [parts, schemes, records, inspections] = await Promise.all([
        Part.find({ projectId: id }).lean(),
        PaintingScheme.find({ projectId: id }).populate('paintId thinnerId').lean(),
        ApplicationRecord.find({ projectId: id }).lean(),
        Inspection.find({ projectId: id })
            .populate({
                path: 'stockItemId',
                select: 'batchNumber dataSheetId',
                populate: { path: 'dataSheetId', select: 'name' }
            })
            .lean()
    ]);

    return {
        ...project,
        id: project._id.toString(),
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        parts: parts.map((p: any) => ({ ...p, id: p._id.toString() })),
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        paintingSchemes: schemes.map((s: any) => ({ ...s, id: s._id.toString() })),
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        applicationRecords: records.map((r: any) => ({ ...r, id: r._id.toString() })),
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        inspections: inspections.map((i: any) => ({ ...i, id: i._id.toString() }))
    };
};

export const updateProject = async (id: string, data: Partial<ProjectData>, organizationId?: string, isGlobalAdmin: boolean = false) => {
    const existing = await Project.findById(id);
    if (!existing) return null;

    // Check ownership
    if (!isGlobalAdmin && organizationId && existing.organizationId && existing.organizationId !== organizationId) {
        console.warn(`Access Denied: Project ${id} belongs to ${existing.organizationId}, user is ${organizationId}`);
        return null;
    }

    const updateData: Partial<ProjectData> & { updatedAt: Date, organizationId?: string } = {
        ...data,
        updatedAt: new Date(),
        startDate: data.startDate ? new Date(data.startDate) : undefined,
        endDate: data.endDate ? new Date(data.endDate) : undefined,
        weightKg: data.weightKg,
    };

    // Adopt if needed
    if (organizationId && !existing.organizationId) {
        updateData.organizationId = organizationId;
    }

    const updated = await Project.findOneAndUpdate({ _id: id }, updateData, { new: true }).lean();
    if (updated) {
        return { ...updated, id: updated._id.toString() };
    }
    return null;
};

export const deleteProject = async (id: string, organizationId?: string, isGlobalAdmin: boolean = false) => {
    const project = await Project.findById(id);
    if (!project) return;

    // Check ownership
    if (!isGlobalAdmin && organizationId && project.organizationId && project.organizationId !== organizationId) {
        throw new Error('Sem permissão para excluir este projeto');
    }

    await Project.findByIdAndDelete(id);

    // Also cleanup related data
    await Promise.all([
        Part.deleteMany({ projectId: id }),
        PaintingScheme.deleteMany({ projectId: id }),
        ApplicationRecord.deleteMany({ projectId: id }),
        Inspection.deleteMany({ projectId: id })
    ]);
};



