"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SectionsService = void 0;
const common_1 = require("@nestjs/common");
const mongoose_1 = require("@nestjs/mongoose");
const section_schema_1 = require("./schemas/section.schema");
const student_schema_1 = require("../students/schemas/student.schema");
const class_schema_1 = require("../classes/schemas/class.schema");
const teacher_schema_1 = require("../teachers/schemas/teacher.schema");
const mongoose_2 = require("mongoose");
const mongo_serializer_1 = require("../common/utils/mongo-serializer");
let SectionsService = class SectionsService {
    sectionModel;
    studentModel;
    classModel;
    teacherModel;
    constructor(sectionModel, studentModel, classModel, teacherModel) {
        this.sectionModel = sectionModel;
        this.studentModel = studentModel;
        this.classModel = classModel;
        this.teacherModel = teacherModel;
    }
    norm(v) {
        return (v || '').trim();
    }
    lc(v) {
        return (v || '').trim().toLowerCase();
    }
    formatSectionName(name) {
        const trimmed = (name || '').trim();
        if (!trimmed)
            return trimmed;
        if (trimmed === trimmed.toUpperCase() && trimmed !== trimmed.toLowerCase()) {
            return trimmed;
        }
        return trimmed
            .toLowerCase()
            .replace(/\b[a-z]/g, c => c.toUpperCase());
    }
    handleDup(err) {
        if (err?.code === 11000) {
            const fields = Object.keys(err?.keyPattern || {});
            if (fields.includes('name') && fields.includes('classId')) {
                throw new common_1.BadRequestException('Section already exists in this class');
            }
            if (fields.includes('classId') && fields.includes('order')) {
                throw new common_1.BadRequestException('Section order must be unique within the class');
            }
            throw new common_1.BadRequestException('Duplicate value');
        }
        throw err;
    }
    async create(dto) {
        const classId = this.norm(dto.classId);
        const classDoc = await this.classModel.findById(classId).lean();
        if (!classDoc) {
            throw new common_1.BadRequestException('Class not found');
        }
        if (dto.assignedTeacherId) {
            const teacherId = this.norm(dto.assignedTeacherId);
            const teacherDoc = await this.teacherModel.findById(teacherId).lean();
            if (!teacherDoc) {
                throw new common_1.BadRequestException('Teacher not found');
            }
        }
        try {
            const doc = await this.sectionModel.create({
                name: this.formatSectionName(dto.name),
                classId,
                assignedTeacherId: dto.assignedTeacherId ? this.norm(dto.assignedTeacherId) : undefined,
                order: dto.order,
            });
            return doc.toJSON();
        }
        catch (err) {
            this.handleDup(err);
        }
    }
    async findAll() {
        const sections = await this.sectionModel
            .find()
            .sort({ classId: 1, order: 1, name: 1 })
            .lean();
        return (0, mongo_serializer_1.toJSON)(sections);
    }
    async findByClass(classId) {
        const sections = await this.sectionModel
            .find({ classId: this.norm(classId) })
            .sort({ order: 1, name: 1 })
            .lean();
        return (0, mongo_serializer_1.toJSON)(sections);
    }
    async findOne(id) {
        const section = await this.sectionModel
            .findById(id)
            .lean();
        return (0, mongo_serializer_1.toJSON)(section);
    }
    async update(id, dto) {
        if (dto.classId !== undefined) {
            const classId = this.norm(dto.classId);
            const classDoc = await this.classModel.findById(classId).lean();
            if (!classDoc) {
                throw new common_1.BadRequestException('Class not found');
            }
        }
        if (dto.assignedTeacherId !== undefined && dto.assignedTeacherId) {
            const teacherId = this.norm(dto.assignedTeacherId);
            const teacherDoc = await this.teacherModel.findById(teacherId).lean();
            if (!teacherDoc) {
                throw new common_1.BadRequestException('Teacher not found');
            }
        }
        const $set = {};
        const $unset = {};
        if (dto.name !== undefined)
            $set.name = this.formatSectionName(dto.name);
        if (dto.classId !== undefined)
            $set.classId = this.norm(dto.classId);
        if (dto.assignedTeacherId !== undefined) {
            if (dto.assignedTeacherId) {
                $set.assignedTeacherId = this.norm(dto.assignedTeacherId);
            }
            else {
                $unset.assignedTeacherId = 1;
            }
        }
        if (dto.order !== undefined)
            $set.order = dto.order;
        const updateOps = {};
        if (Object.keys($set).length > 0)
            updateOps.$set = $set;
        if (Object.keys($unset).length > 0)
            updateOps.$unset = $unset;
        try {
            const section = await this.sectionModel
                .findByIdAndUpdate(id, updateOps, { new: true, runValidators: true })
                .lean();
            return (0, mongo_serializer_1.toJSON)(section);
        }
        catch (err) {
            this.handleDup(err);
        }
    }
    async delete(id) {
        const studentCount = await this.studentModel.countDocuments({ sectionId: id });
        if (studentCount > 0) {
            throw new common_1.BadRequestException(`Cannot delete section: ${studentCount} student(s) are assigned to this section. Please reassign or delete them first.`);
        }
        const section = await this.sectionModel
            .findByIdAndDelete(id)
            .lean();
        return (0, mongo_serializer_1.toJSON)(section);
    }
};
exports.SectionsService = SectionsService;
exports.SectionsService = SectionsService = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, mongoose_1.InjectModel)(section_schema_1.Section.name)),
    __param(1, (0, mongoose_1.InjectModel)(student_schema_1.Student.name)),
    __param(2, (0, mongoose_1.InjectModel)(class_schema_1.Class.name)),
    __param(3, (0, mongoose_1.InjectModel)(teacher_schema_1.Teacher.name)),
    __metadata("design:paramtypes", [mongoose_2.Model,
        mongoose_2.Model,
        mongoose_2.Model,
        mongoose_2.Model])
], SectionsService);
//# sourceMappingURL=sections.service.js.map