import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { Types } from 'mongoose';
import { ModelsService } from 'src/models/models.service';
import { CommonService } from 'src/common/common.service';
import { TranslationService } from 'src/common/services/translation.service';
import { RegionListDto, CreateRegionDto, UpdateRegionDto } from './dto/region.dto';

@Injectable()
export class RegionService {
    constructor(
        private readonly models: ModelsService,
        private readonly common: CommonService,
        private readonly translationService: TranslationService
    ) { }

    private t(key: string, lang: string) {
        return this.translationService.translate(key, lang);
    }

    private toObjectId(id: string, lang: string) {
        if (!Types.ObjectId.isValid(id)) {
            throw new HttpException({ message: this.t('REGION_NOT_FOUND', lang) }, HttpStatus.NOT_FOUND);
        }
        return new Types.ObjectId(id);
    }

    private async assertNameFree(name: string, lang: string, excludeId?: Types.ObjectId) {
        const filter: any = { name };
        if (excludeId) filter._id = { $ne: excludeId };
        const existing = await this.models.RegionModel.findOne(filter).collation({ locale: 'en', strength: 2 }).lean();
        if (existing) {
            throw new HttpException({ message: this.t('REGION_ALREADY_EXISTS', lang) }, HttpStatus.BAD_REQUEST);
        }
    }

    async create(dto: CreateRegionDto, lang: string) {
        await this.assertNameFree(dto.name, lang);
        const region = await this.models.RegionModel.create({ name: dto.name });
        return this.common.successResponse(this.t('REGION_CREATED', lang), region);
    }

    async list(query: RegionListDto, lang: string) {
        const { page, limit, search, is_active } = query;
        const filter: any = {};
        if (search) filter.name = { $regex: search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), $options: 'i' };
        if (is_active !== undefined) filter.is_active = is_active === 'true';

        const [total, regions] = await Promise.all([
            this.models.RegionModel.countDocuments(filter),
            this.models.RegionModel.find(filter)
                .sort({ created_at: 1 })
                .skip((page - 1) * limit)
                .limit(limit)
                .lean(),
        ]);

        return this.common.paginatedResponse(this.t('REGIONS_FETCHED', lang), regions, total, page, limit);
    }

    async getById(id: string, lang: string) {
        const region = await this.models.RegionModel.findById(this.toObjectId(id, lang)).lean();
        if (!region) {
            throw new HttpException({ message: this.t('REGION_NOT_FOUND', lang) }, HttpStatus.NOT_FOUND);
        }
        return this.common.successResponse(this.t('REGION_FETCHED', lang), region);
    }

    async update(id: string, dto: UpdateRegionDto, lang: string) {
        const _id = this.toObjectId(id, lang);
        const region = await this.models.RegionModel.findById(_id);
        if (!region) {
            throw new HttpException({ message: this.t('REGION_NOT_FOUND', lang) }, HttpStatus.NOT_FOUND);
        }

        if (dto.name !== undefined && dto.name.toLowerCase() !== region.name.toLowerCase()) {
            await this.assertNameFree(dto.name, lang, _id);
        }
        if (dto.name !== undefined) region.name = dto.name;
        if (dto.is_active !== undefined) region.is_active = dto.is_active;
        await region.save();

        return this.common.successResponse(this.t('REGION_UPDATED', lang), region);
    }
}
