"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.AcademicYearService = void 0;
const common_1 = require("@nestjs/common");
const mongoose_1 = require("@nestjs/mongoose");
const mongoose_2 = require("mongoose");
const academic_year_repository_1 = require("./academic-year.repository");
const audit_service_1 = require("../audit/audit.service");
const assert_found_1 = require("../common/utils/assert-found");
const student_schema_1 = require("../students/schemas/student.schema");
const academic_year_utils_1 = require("./academic-year.utils");
function toDate(d) { return new Date(d); }
let AcademicYearService = class AcademicYearService {
    repo;
    audit;
    studentModel;
    constructor(repo, audit, studentModel) {
        this.repo = repo;
        this.audit = audit;
        this.studentModel = studentModel;
    }
    async create(dto, ctx) {
        const start = toDate(dto.startDate);
        const end = toDate(dto.endDate);
        if (end <= start)
            throw new common_1.BadRequestException('endDate must be greater than startDate');
        const computedName = (0, academic_year_utils_1.nameFromDates)(start, end);
        const useName = dto.name ?? computedName;
        const existing = await this.repo.findOne({ name: useName });
        if (existing)
            return existing;
        if (await this.repo.hasOverlap(start, end))
            throw new common_1.ConflictException('Date range overlaps');
        const created = await this.repo.create({
            name: useName, startDate: start, endDate: end, isActive: dto.isActive ?? true, isCurrent: false,
        });
        await this.audit.log({ entity: 'AcademicYear', entityId: String(created._id), action: 'create', after: created, ctx });
        return created;
    }
    findAll(includeInactive = true) {
        const filter = includeInactive ? {} : { isActive: true };
        return this.repo.findMany(filter);
    }
    async findOne(id) {
        const found = await this.repo.findById(id);
        (0, assert_found_1.assertFound)(found, 'Academic year not found');
        return found;
    }
    async getCurrent() {
        const current = await this.repo.findOne({ isCurrent: true });
        if (current)
            return current;
        const activeYears = await this.repo.findMany({ isActive: true });
        if (activeYears.length === 0)
            return null;
        const sorted = activeYears.sort((a, b) => {
            const dateA = new Date(a.startDate).getTime();
            const dateB = new Date(b.startDate).getTime();
            return dateB - dateA;
        });
        return sorted[0];
    }
    async findForTopbar(userId, role) {
        if (role?.toLowerCase() === 'student' && userId) {
            try {
                const student = await this.studentModel.findById(userId, { academicYearId: 1 }).lean();
                if (student?.academicYearId) {
                    const studentYear = await this.repo.findById(String(student.academicYearId));
                    if (studentYear) {
                        return [{
                                _id: studentYear._id,
                                name: studentYear.name,
                                label: studentYear.name,
                                displayLabel: (0, academic_year_utils_1.displayLabelFromDates)(studentYear.startDate, studentYear.endDate),
                                isCurrent: studentYear.isCurrent,
                                isActive: studentYear.isActive,
                            }];
                    }
                }
                return [];
            }
            catch (error) {
                console.error('Error fetching student academic year:', error);
                return [];
            }
        }
        const activeYears = await this.repo.findMany({ isActive: true });
        return activeYears.map(year => ({
            _id: year._id,
            name: year.name,
            label: year.name,
            displayLabel: (0, academic_year_utils_1.displayLabelFromDates)(year.startDate, year.endDate),
            isCurrent: year.isCurrent,
            isActive: year.isActive,
        })).sort((a, b) => {
            return b.name.localeCompare(a.name);
        });
    }
    async setCurrent(id, ctx) {
        const before = await this.findOne(id);
        if (!before.isActive)
            throw new common_1.BadRequestException('Cannot set current on an inactive year');
        await this.repo.unsetAllCurrent();
        try {
            const after = await this.repo.updateById(id, { isCurrent: true });
            (0, assert_found_1.assertFound)(after);
            await this.audit.log({ entity: 'AcademicYear', entityId: id, action: 'set-current', before, after, ctx });
            return after;
        }
        catch (e) {
            if (e?.code === 11000)
                throw new common_1.ConflictException('Another request set current year. Refresh and try again.');
            throw e;
        }
    }
    async setActive(id, active, ctx) {
        const before = await this.findOne(id);
        if (!active && before.isCurrent)
            throw new common_1.BadRequestException('Cannot deactivate the current year');
        const after = await this.repo.updateById(id, { isActive: active });
        (0, assert_found_1.assertFound)(after);
        await this.audit.log({ entity: 'AcademicYear', entityId: id, action: 'activate', before, after, ctx });
        return after;
    }
    async update(id, dto, ifMatch, ctx) {
        const current = await this.findOne(id);
        if (ifMatch) {
            const tag = String(new Date(current.updatedAt).getTime());
            if (tag !== ifMatch)
                throw new common_1.PreconditionFailedException('ETag mismatch');
        }
        const nextStart = dto.startDate ? toDate(dto.startDate) : current.startDate;
        const nextEnd = dto.endDate ? toDate(dto.endDate) : current.endDate;
        if (nextEnd <= nextStart)
            throw new common_1.BadRequestException('endDate must be greater than startDate');
        if (await this.repo.hasOverlap(nextStart, nextEnd, id))
            throw new common_1.ConflictException('Date range overlaps');
        const computedName = (0, academic_year_utils_1.nameFromDates)(nextStart, nextEnd);
        const next = {
            name: dto.name ?? computedName,
            startDate: nextStart,
            endDate: nextEnd,
            isActive: dto.isActive ?? current.isActive,
        };
        const after = await this.repo.updateById(id, next);
        (0, assert_found_1.assertFound)(after);
        await this.audit.log({ entity: 'AcademicYear', entityId: id, action: 'update', before: current, after, ctx });
        return after;
    }
    async remove(id, ctx) {
        const before = await this.findOne(id);
        if (before.isCurrent)
            throw new common_1.BadRequestException('Cannot delete the current year');
        const after = await this.repo.updateById(id, { isActive: false });
        (0, assert_found_1.assertFound)(after);
        await this.audit.log({ entity: 'AcademicYear', entityId: id, action: 'delete', before, after, ctx });
        return after;
    }
};
exports.AcademicYearService = AcademicYearService;
exports.AcademicYearService = AcademicYearService = __decorate([
    (0, common_1.Injectable)(),
    __param(2, (0, mongoose_1.InjectModel)(student_schema_1.Student.name)),
    __metadata("design:paramtypes", [academic_year_repository_1.AcademicYearRepository,
        audit_service_1.AuditService,
        mongoose_2.Model])
], AcademicYearService);
//# sourceMappingURL=academic-year.service.js.map