import { CalendarLayerType, CalendarSystemType, Prisma } from '@prisma/client';
import { prisma } from '../../config/database';
import { sharedCalendarService } from './shared-calendar.service';
import { AppError } from '../../middleware/error-handler';
import { logger } from '../../utils/logger';

import type { CreateAdminViewInput, UpdateAdminViewInput } from './admin-calendar.schemas';

const MEMBER_COLORS = [
  '#1890ff', '#52c41a', '#fa8c16', '#eb2f96', '#722ed1',
  '#13c2c2', '#faad14', '#f5222d', '#2f54eb', '#a0d911',
];

export const adminCalendarService = {
  async listAdminViews(userId: string) {
    const views = await prisma.sharedCalendarView.findMany({
      where: { viewType: 'ROLE_BASED', ownerId: userId },
      include: {
        owner: { select: { id: true, name: true, email: true } },
      },
      orderBy: { createdAt: 'desc' },
    });

    // Count matching users for each view
    const viewsWithCounts = await Promise.all(
      views.map(async (view) => {
        const roles = (view.autoIncludeRoles as string[]) || [];
        const count = await prisma.user.count({
          where: { role: { in: roles as any[] }, status: 'ACTIVE' },
        });
        return { ...view, userCount: count };
      }),
    );

    return viewsWithCounts;
  },

  async createAdminView(userId: string, data: CreateAdminViewInput) {
    const view = await prisma.sharedCalendarView.create({
      data: {
        name: data.name,
        description: data.description,
        ownerId: userId,
        viewType: 'ROLE_BASED',
        autoIncludeRoles: data.autoIncludeRoles as unknown as Prisma.InputJsonValue,
        includedLayerTypes: data.includedLayerTypes as unknown as Prisma.InputJsonValue,
        shareScope: 'MEMBERS',
      },
      include: {
        owner: { select: { id: true, name: true, email: true } },
      },
    });

    return view;
  },

  async updateAdminView(userId: string, viewId: string, data: UpdateAdminViewInput) {
    const view = await prisma.sharedCalendarView.findFirst({
      where: { id: viewId, ownerId: userId, viewType: 'ROLE_BASED' },
    });
    if (!view) throw new AppError(404, 'Admin view not found or not owner', 'NOT_FOUND');

    return prisma.sharedCalendarView.update({
      where: { id: viewId },
      data: {
        ...(data.name !== undefined && { name: data.name }),
        ...(data.description !== undefined && { description: data.description }),
        ...(data.autoIncludeRoles !== undefined && {
          autoIncludeRoles: data.autoIncludeRoles as unknown as Prisma.InputJsonValue,
        }),
        ...(data.includedLayerTypes !== undefined && {
          includedLayerTypes: data.includedLayerTypes as unknown as Prisma.InputJsonValue,
        }),
      },
      include: {
        owner: { select: { id: true, name: true, email: true } },
      },
    });
  },

  async deleteAdminView(userId: string, viewId: string) {
    const view = await prisma.sharedCalendarView.findFirst({
      where: { id: viewId, ownerId: userId, viewType: 'ROLE_BASED' },
    });
    if (!view) throw new AppError(404, 'Admin view not found or not owner', 'NOT_FOUND');

    await prisma.sharedCalendarView.delete({ where: { id: viewId } });
  },

  async getAdminViewItems(
    viewId: string,
    userId: string,
    startDate: string,
    endDate: string,
  ) {
    const view = await prisma.sharedCalendarView.findFirst({
      where: { id: viewId, ownerId: userId, viewType: 'ROLE_BASED' },
    });
    if (!view) throw new AppError(404, 'Admin view not found or not owner', 'NOT_FOUND');

    const roles = (view.autoIncludeRoles as string[]) || [];
    const includedLayerTypes = (view.includedLayerTypes as string[]) || [];

    // Query users by role (live, no member rows)
    const users = await prisma.user.findMany({
      where: { role: { in: roles as any[] }, status: 'ACTIVE' },
      orderBy: { name: 'asc' },
      take: 50,
      select: { id: true, name: true, email: true, role: true },
    });

    const totalUsers = await prisma.user.count({
      where: { role: { in: roles as any[] }, status: 'ACTIVE' },
    });

    const start = new Date(startDate);
    const end = new Date(endDate);
    const allItems: any[] = [];

    for (let i = 0; i < users.length; i++) {
      const user = users[i];
      const color = MEMBER_COLORS[i % MEMBER_COLORS.length];

      // Get this user's system layers matching includedLayerTypes
      const layers = await prisma.calendarLayer.findMany({
        where: {
          userId: user.id,
          isEnabled: true,
          layerType: CalendarLayerType.SYSTEM,
          systemType: { in: includedLayerTypes as CalendarSystemType[] },
        },
      });

      for (const layer of layers) {
        try {
          const items = await sharedCalendarService.getSystemLayerItems(
            user.id,
            layer,
            start,
            end,
          );

          for (const item of items) {
            allItems.push({
              ...item,
              userId: user.id,
              userName: user.name || user.email,
              userColor: color,
            });
          }
        } catch (err) {
          logger.debug(`Failed to fetch system layer items for user ${user.id}:`, err);
        }
      }
    }

    // Sort by date then time
    allItems.sort((a, b) => {
      const dc = a.date.localeCompare(b.date);
      return dc !== 0 ? dc : a.startTime.localeCompare(b.startTime);
    });

    return {
      items: allItems,
      users: users.map((u, i) => ({
        ...u,
        color: MEMBER_COLORS[i % MEMBER_COLORS.length],
      })),
      totalUsers,
      truncated: totalUsers > 50,
    };
  },
};
