import {
  Injectable,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { CrmPrismaService } from '../prisma/crm-prisma.service';
import { CreateActivityDto } from './dto/create-activity.dto';
import { UpdateActivityDto } from './dto/update-activity.dto';
import { QueryActivitiesDto } from './dto/query-activities.dto';
import { Prisma } from '.prisma/crm-client';

@Injectable()
export class ActivitiesService {
  constructor(private readonly prisma: CrmPrismaService) {}

  async create(tenantId: string, userId: string, dto: CreateActivityDto) {
    // Mindestens contactId oder companyId muss gesetzt sein
    if (!dto.contactId && !dto.companyId) {
      throw new BadRequestException(
        'Mindestens contactId oder companyId muss angegeben werden',
      );
    }

    // Kontakt validieren (falls gesetzt)
    if (dto.contactId) {
      const contact = await this.prisma.contact.findFirst({
        where: { id: dto.contactId, tenantId },
      });
      if (!contact) {
        throw new NotFoundException('Kontakt nicht gefunden');
      }
    }

    // Unternehmen validieren (falls gesetzt)
    if (dto.companyId) {
      const company = await this.prisma.company.findFirst({
        where: { id: dto.companyId, tenantId },
      });
      if (!company) {
        throw new NotFoundException('Unternehmen nicht gefunden');
      }
    }

    return this.prisma.activity.create({
      data: {
        tenantId,
        contactId: dto.contactId,
        companyId: dto.companyId,
        type: dto.type,
        subject: dto.subject,
        description: dto.description,
        scheduledAt: dto.scheduledAt ? new Date(dto.scheduledAt) : undefined,
        completedAt: dto.completedAt ? new Date(dto.completedAt) : undefined,
        createdBy: userId,
      },
      include: {
        contact: {
          select: { id: true, firstName: true, lastName: true, companyName: true },
        },
        company: {
          select: { id: true, name: true },
        },
      },
    });
  }

  async findAll(tenantId: string, query: QueryActivitiesDto) {
    const page = query.page ?? 1;
    const pageSize = query.pageSize ?? 25;

    const where: Prisma.ActivityWhereInput = { tenantId };

    // Aggregierter Company-Feed: direkte + verknuepfte Kontakt-Aktivitaeten
    if (query.companyId && query.includeContacts) {
      const contactIds = await this.prisma.contact
        .findMany({
          where: { tenantId, companyId: query.companyId },
          select: { id: true },
        })
        .then((contacts) => contacts.map((c) => c.id));

      where.OR = [
        { companyId: query.companyId },
        ...(contactIds.length > 0
          ? [{ contactId: { in: contactIds } }]
          : []),
      ];
    } else if (query.companyId) {
      where.companyId = query.companyId;
    } else if (query.contactId) {
      where.contactId = query.contactId;
    }

    if (query.type) {
      where.type = query.type;
    }

    const allowedSortFields = ['createdAt', 'updatedAt', 'scheduledAt', 'subject'];
    const sortField = allowedSortFields.includes(query.sort ?? '')
      ? (query.sort as string)
      : 'createdAt';

    const [data, total] = await Promise.all([
      this.prisma.activity.findMany({
        where,
        skip: (page - 1) * pageSize,
        take: pageSize,
        orderBy: { [sortField]: query.order ?? 'desc' },
        include: {
          contact: {
            select: { id: true, firstName: true, lastName: true, companyName: true },
          },
          company: {
            select: { id: true, name: true },
          },
        },
      }),
      this.prisma.activity.count({ where }),
    ]);

    return { data, total, page, pageSize };
  }

  async findOne(tenantId: string, id: string) {
    const activity = await this.prisma.activity.findFirst({
      where: { id, tenantId },
      include: {
        contact: true,
        company: { select: { id: true, name: true } },
      },
    });

    if (!activity) {
      throw new NotFoundException('Aktivitaet nicht gefunden');
    }

    return activity;
  }

  async update(
    tenantId: string,
    id: string,
    userId: string,
    dto: UpdateActivityDto,
  ) {
    await this.findOne(tenantId, id);

    return this.prisma.activity.update({
      where: { id },
      data: {
        ...dto,
        scheduledAt: dto.scheduledAt ? new Date(dto.scheduledAt) : undefined,
        completedAt: dto.completedAt ? new Date(dto.completedAt) : undefined,
        updatedBy: userId,
      },
      include: {
        contact: {
          select: { id: true, firstName: true, lastName: true, companyName: true },
        },
        company: {
          select: { id: true, name: true },
        },
      },
    });
  }

  async remove(tenantId: string, id: string) {
    await this.findOne(tenantId, id);
    return this.prisma.activity.delete({ where: { id } });
  }

  /** Alle offenen Aufgaben (TASK + FOLLOWUP, nicht erledigt) */
  async findOpenTasks(tenantId: string) {
    return this.prisma.activity.findMany({
      where: {
        tenantId,
        type: { in: ['TASK', 'FOLLOWUP'] },
        completedAt: null,
      },
      orderBy: [
        { scheduledAt: { sort: 'asc', nulls: 'last' } },
        { createdAt: 'desc' },
      ],
      include: {
        contact: {
          select: { id: true, firstName: true, lastName: true, companyName: true },
        },
        company: {
          select: { id: true, name: true },
        },
      },
    });
  }
}
