import { Router } from 'express';
import prisma from '../lib/prisma';
import { asyncHandler, sendSuccess, getPagination, buildPaginationMeta, AppError, paramId } from '../lib/utils';
import { categoryJobCountFilter, categoryWorkerSkillCountFilter } from '../lib/serviceArea';
import { categorySearchOrClauses } from '../lib/searchQuery';
import { optionalAuth, authenticate, authorize } from '../middleware/auth';

const router = Router();

function slugify(name: string) {
  return name
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-|-$/g, '');
}

function categoryCountInclude(areaParam: unknown) {
  const workerSkillWhere = categoryWorkerSkillCountFilter(areaParam);
  const jobWhere = categoryJobCountFilter(areaParam);

  return {
    _count: {
      select: {
        workerSkills: workerSkillWhere ? { where: workerSkillWhere } : true,
        jobs: jobWhere ? { where: jobWhere } : true,
      },
    },
  };
}

router.get(
  '/',
  optionalAuth,
  asyncHandler(async (req, res) => {
    const { page, limit, skip } = getPagination(req.query);
    const search = req.query.search as string | undefined;
    const isActive = req.query.isActive !== 'false';

    const where = {
      deletedAt: null,
      ...(isActive ? { isActive: true } : {}),
      ...(search
        ? {
            OR: categorySearchOrClauses(search),
          }
        : {}),
    };

    const [categories, total] = await Promise.all([
      prisma.category.findMany({
        where,
        orderBy: { sortOrder: 'asc' },
        skip,
        take: limit,
        include: categoryCountInclude(req.query.area),
      }),
      prisma.category.count({ where }),
    ]);

    sendSuccess(res, categories, undefined, 200, buildPaginationMeta(total, page, limit));
  })
);

router.post(
  '/',
  authenticate,
  authorize('ADMIN'),
  asyncHandler(async (req, res) => {
    const { name, description, icon, sortOrder } = req.body;
    if (!name || typeof name !== 'string' || !name.trim()) {
      throw new AppError('Category name is required', 400);
    }

    const baseSlug = slugify(name);
    let slug = baseSlug;
    let suffix = 1;
    while (await prisma.category.findFirst({ where: { slug, deletedAt: null } })) {
      slug = `${baseSlug}-${suffix++}`;
    }

    const category = await prisma.category.create({
      data: {
        name: name.trim(),
        slug,
        description: description?.trim() || null,
        icon: icon?.trim() || null,
        sortOrder: typeof sortOrder === 'number' ? sortOrder : 0,
      },
    });

    sendSuccess(res, category, 'Category created', 201);
  })
);

router.patch(
  '/:id',
  authenticate,
  authorize('ADMIN'),
  asyncHandler(async (req, res) => {
    const { name, description, icon, isActive, sortOrder } = req.body;
    const data: Record<string, unknown> = {};

    if (name !== undefined) {
      if (typeof name !== 'string' || !name.trim()) throw new AppError('Invalid name', 400);
      data.name = name.trim();
    }
    if (description !== undefined) data.description = description?.trim() || null;
    if (icon !== undefined) data.icon = icon?.trim() || null;
    if (typeof isActive === 'boolean') data.isActive = isActive;
    if (typeof sortOrder === 'number') data.sortOrder = sortOrder;

    if (Object.keys(data).length === 0) {
      throw new AppError('No valid fields to update', 400);
    }

    const category = await prisma.category.update({
      where: { id: paramId(req.params.id) },
      data,
    });

    sendSuccess(res, category, 'Category updated');
  })
);

router.get(
  '/:slug',
  asyncHandler(async (req, res) => {
    const slug = paramId(req.params.slug);
    const category = await prisma.category.findFirst({
      where: { slug, deletedAt: null },
      include: categoryCountInclude(req.query.area),
    });

    if (!category) {
      throw new AppError('Category not found', 404);
    }

    sendSuccess(res, category);
  })
);

export default router;
