import { Injectable } from "@nestjs/common";
import { InjectModel } from "@nestjs/mongoose";
import { Model, Types } from "mongoose";
import { Exercise, ExerciseDocument } from "./schemas/exercise.schema";
import { ExerciseCategory, ExerciseCategoryDocument } from "./schemas/exercise-category.schema";
import { CreateExerciseDto } from "./dto/create-exercise.dto";
import { UpdateExerciseDto } from "./dto/update-exercise.dto";
import { CreateExerciseCategoryDto } from "./dto/create-exercise-category.dto";
import { UpdateExerciseCategoryDto } from "./dto/update-exercise-category.dto";
import { Request, Response } from "express";
import { ResponseService } from "src/common/service/response.service";

@Injectable()
export class ExerciseService {
  constructor(
    @InjectModel(Exercise.name)
    private exerciseModel: Model<ExerciseDocument>,
    @InjectModel(ExerciseCategory.name)
    private categoryModel: Model<ExerciseCategoryDocument>,
    private readonly resService: ResponseService
  ) {}

  // ─── Exercise Category CRUD ───────────────────────────────────────────────

  async createCategory(body: CreateExerciseCategoryDto, req: Request, res: Response) {
    try {
      const category = await this.categoryModel.create({ ...body });
      console.log(category , "  category");
      return this.resService.created(res, category, "Category created successfully", req);
    } catch (error: any) {
      return this.resService.serverError(res, "SOMETHING_WENT_WRONG", req, error.message || error);
    }
  }

  async getAllCategories(req: Request, res: Response) {
    try {
      const lang = (req.headers["accept-language"] as string) || "en";
      const data = await this.categoryModel.find({ deleted_at: null, status: 1 }).sort({ createdAt: 1 });

      const localized = data.map((item) => {
        const doc = item.toObject();
        return {
          ...doc,
          name: doc.name?.[lang] ?? doc.name?.["en"],
          fields: doc.fields.map((f) => ({
            ...f,
            label: f.label?.[lang] ?? f.label?.["en"],
          })),
        };
      });

      return this.resService.success(res, "success", req, localized);
    } catch (error: any) {
      return this.resService.serverError(res, "SOMETHING_WENT_WRONG", req, error.message || error);
    }
  }

  async getCategoryById(id: string, req: Request, res: Response) {
    try {
      const lang = (req.headers["accept-language"] as string) || "en";
      const category = await this.categoryModel.findOne({ _id: id, deleted_at: null });

      if (!category) return this.resService.notFound(res, "Category not found", req);

      const doc = category.toObject();
      return this.resService.success(res, "success", req, {
        ...doc,
        name: doc.name?.[lang] ?? doc.name?.["en"],
        fields: doc.fields.map((f) => ({
          ...f,
          label: f.label?.[lang] ?? f.label?.["en"],
        })),
      });
    } catch (error: any) {
      return this.resService.serverError(res, "SOMETHING_WENT_WRONG", req, error.message || error);
    }
  }

  async updateCategory(id: string, body: UpdateExerciseCategoryDto, req: Request, res: Response) {
    try {
      const category = await this.categoryModel.findOne({ _id: id, deleted_at: null });
      if (!category) return this.resService.notFound(res, "Category not found", req);

      const updated = await this.categoryModel.findByIdAndUpdate(id, { ...body }, { new: true });
      return this.resService.success(res, "Category updated successfully", req, updated);
    } catch (error: any) {
      return this.resService.serverError(res, "SOMETHING_WENT_WRONG", req, error.message || error);
    }
  }

  async deleteCategory(id: string, req: Request, res: Response) {
    try {
      const category = await this.categoryModel.findOne({ _id: id, deleted_at: null });
      if (!category) return this.resService.notFound(res, "Category not found", req);

      await this.categoryModel.findByIdAndUpdate(id, { deleted_at: new Date() });
      return this.resService.success(res, "Category deleted successfully", req);
    } catch (error: any) {
      return this.resService.serverError(res, "SOMETHING_WENT_WRONG", req, error.message || error);
    }
  }

  // ─── Exercise CRUD ────────────────────────────────────────────────────────

  async createExercise(body: CreateExerciseDto, req: Request, res: Response) {
    try {
      const exercise = await this.exerciseModel.create({ ...body });
      return this.resService.created(res, exercise, "exercise_created_successfully", req);
    } catch (error: any) {
      return this.resService.serverError(res, "SOMETHING_WENT_WRONG", req, error.message || error);
    }
  }

  async getAllExercisesNoPagination(req: Request, res: Response, categoryId?: string) {
    try {
      const lang = (req.headers["accept-language"] as string) || "en";
      const filter: any = { deleted_at: null, status: 1 };
      if (categoryId) filter.category = new Types.ObjectId(categoryId);

      const data = await this.exerciseModel
        .find(filter)
        .populate("category")
        .populate("targetedBodyParts")
        .sort({ createdAt: -1 });

      const localized = data.map((item) => {
        const doc = item.toObject() as any;
        return {
          ...doc,
          name: doc.name?.[lang],
          description: doc.description?.[lang],
          category: doc.category
            ? {
                ...doc.category,
                name: doc.category.name?.[lang] ?? doc.category.name?.["en"],
              }
            : null,
          targetedBodyParts: (doc.targetedBodyParts ?? []).map((bp: any) => ({
            ...bp,
            name: bp.name?.[lang] ?? bp.name?.["en"],
          })),
        };
      });

      localized.sort((a, b) =>
        (a.name ?? "").localeCompare(b.name ?? "", lang, { sensitivity: "base" })
      );

      return this.resService.success(res, "success", req, localized);
    } catch (error: any) {
      return this.resService.serverError(res, "SOMETHING_WENT_WRONG", req, error.message || error);
    }
  }

  async getAllExercises(
    req: Request,
    res: Response,
    page: number,
    limit: number,
    search: string,
    status: string,
    categoryId?: string,
  ) {
    try {
      const lang = (req.headers["accept-language"] as string) || "en";
      console.log("lang", lang);
      page = Number(page) || 1;
      limit = Number(limit) || 10;
      const skip = (page - 1) * limit;

      const filter: any = { deleted_at: null };

      if (status !== undefined && status !== null && status !== "") {
        filter["status"] = Number(status);
      }

      if (categoryId) filter.category = new Types.ObjectId(categoryId);

      if (search) {
        filter.$or = [
          { [`name.${lang}`]: { $regex: search, $options: "i" } },
          { [`description.${lang}`]: { $regex: search, $options: "i" } },
        ];
      }

      const [data, total] = await Promise.all([
        this.exerciseModel
          .find(filter)
          .populate("category")
          .populate("targetedBodyParts")
          .collation({ locale: lang, strength: 1 })
          .sort({ [`name.${lang}`]: 1 })
          .skip(skip)
          .limit(limit),
        this.exerciseModel.countDocuments(filter),
      ]);

      const localizedData = data.map((item) => {
        const doc = item.toObject() as any;
        return {
          ...doc,
          name: doc.name?.[lang],
          description: doc.description?.[lang],
          category: doc.category
            ? {
                ...doc.category,
                name: doc.category.name?.[lang] ?? doc.category.name?.["en"],
              }
            : null,
          targetedBodyParts: (doc.targetedBodyParts ?? []).map((bp: any) => ({
            ...bp,
            name: bp.name?.[lang] ?? bp.name?.["en"],
          })),
        };
      });

      return this.resService.success(res, "success", req, {
        items: localizedData,
        total,
        page,
        limit,
        pages: Math.ceil(total / limit),
      });
    } catch (error: any) {
      return this.resService.serverError(res, "SOMETHING_WENT_WRONG", req, error.message || error);
    }
  }

  async getExerciseById(id: string, req: Request, res: Response) {
    try {
      const lang = (req.headers["accept-language"] as string) || "en";
      const exercise = await this.exerciseModel
        .findOne({ _id: id, deleted_at: null })
        .populate("category")
        .populate("targetedBodyParts");

      if (!exercise) return this.resService.notFound(res, "data_not_found", req);

      const doc = exercise.toObject() as any;
      return this.resService.success(res, "success", req, {
        ...doc,
        name: doc.name?.[lang],
        description: doc.description?.[lang],
        category: doc.category
          ? {
              ...doc.category,
              name: doc.category.name?.[lang] ?? doc.category.name?.["en"],
            }
          : null,
        targetedBodyParts: (doc.targetedBodyParts ?? []).map((bp: any) => ({
          ...bp,
          name: bp.name?.[lang] ?? bp.name?.["en"],
        })),
      });
    } catch (error: any) {
      return this.resService.serverError(res, "SOMETHING_WENT_WRONG", req, error.message || error);
    }
  }

  async updateExercise(id: string, body: UpdateExerciseDto, req: Request, res: Response) {
    try {
      const exercise = await this.exerciseModel.findOne({ _id: id, deleted_at: null });
      if (!exercise) return this.resService.notFound(res, "data_not_found", req);

      const updated = await this.exerciseModel.findByIdAndUpdate(id, { ...body }, { new: true });
      return this.resService.success(res, "exercise_updated_successfully", req, updated);
    } catch (error: any) {
      return this.resService.serverError(res, "SOMETHING_WENT_WRONG", req, error.message || error);
    }
  }

async deleteExercise(id: string, req: Request, res: Response) {
  try {
    const deletedExercise = await this.exerciseModel.findByIdAndDelete(id);

    if (!deletedExercise) {
      return this.resService.notFound(res, "data_not_found", req);
    }

    return this.resService.success(
      res,
      "deleted_successfully",
      req,
    );
  } catch (error: any) {
    return this.resService.serverError(
      res,
      "SOMETHING_WENT_WRONG",
      req,
      error.message || error,
    );
  }
}

}
