import prisma from '../../config/database';
import { AppError } from '../../shared/middleware/errorHandler';
import { AuditLogger } from '../../shared/utils/auditLogger';
import { Prisma } from '@prisma/client';

interface CreateDealData {
  name: string;
  contactId: string;
  structure: string; // B2B, B2C, B2G, PARTNERSHIP
  pipelineId: string;
  stage: string;
  estimatedValue: number;
  probability?: number;
  expectedCloseDate?: Date;
  ownerId: string;
  fiscalYear: number;
}

interface UpdateDealData extends Partial<CreateDealData> {
  stage?: string;
  actualValue?: number;
  actualCloseDate?: Date;
  wonReason?: string;
  lostReason?: string;
  status?: string;
}

class DealsService {
  async create(data: CreateDealData, userId: string) {
    // Generate deal number
    const dealNumber = await this.generateDealNumber();

    const deal = await prisma.deal.create({
      data: {
        dealNumber,
        name: data.name,
        contactId: data.contactId,
        structure: data.structure,
        pipelineId: data.pipelineId,
        stage: data.stage,
        estimatedValue: data.estimatedValue,
        probability: data.probability,
        expectedCloseDate: data.expectedCloseDate,
        ownerId: data.ownerId,
        fiscalYear: data.fiscalYear,
        currency: 'SAR',
      },
      include: {
        contact: {
          select: {
            id: true,
            name: true,
            email: true,
            phone: true,
          },
        },
        owner: {
          select: {
            id: true,
            email: true,
            username: true,
          },
        },
        pipeline: true,
      },
    });

    await AuditLogger.log({
      entityType: 'DEAL',
      entityId: deal.id,
      action: 'CREATE',
      userId,
    });

    return deal;
  }

  async findAll(filters: any, page: number, pageSize: number) {
    const skip = (page - 1) * pageSize;

    const where: Prisma.DealWhereInput = {};

    if (filters.search) {
      where.OR = [
        { name: { contains: filters.search, mode: 'insensitive' } },
        { dealNumber: { contains: filters.search } },
      ];
    }

    if (filters.structure) {
      where.structure = filters.structure;
    }

    if (filters.stage) {
      where.stage = filters.stage;
    }

    if (filters.status) {
      where.status = filters.status;
    }

    if (filters.ownerId) {
      where.ownerId = filters.ownerId;
    }

    if (filters.fiscalYear) {
      where.fiscalYear = parseInt(filters.fiscalYear);
    }

    const total = await prisma.deal.count({ where });

    const deals = await prisma.deal.findMany({
      where,
      skip,
      take: pageSize,
      include: {
        contact: {
          select: {
            id: true,
            name: true,
            email: true,
          },
        },
        owner: {
          select: {
            id: true,
            email: true,
            username: true,
          },
        },
        pipeline: true,
      },
      orderBy: {
        createdAt: 'desc',
      },
    });

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

  async findById(id: string) {
    const deal = await prisma.deal.findUnique({
      where: { id },
      include: {
        contact: {
          include: {
            categories: true,
          },
        },
        owner: {
          select: {
            id: true,
            email: true,
            username: true,
            employee: {
              select: {
                firstName: true,
                lastName: true,
                position: true,
                department: true,
              },
            },
          },
        },
        pipeline: true,
        quotes: {
          orderBy: {
            version: 'desc',
          },
        },
        costSheets: {
          orderBy: {
            version: 'desc',
          },
        },
        activities: {
          orderBy: {
            createdAt: 'desc',
          },
          take: 20,
        },
        notes: {
          orderBy: {
            createdAt: 'desc',
          },
        },
        attachments: {
          orderBy: {
            uploadedAt: 'desc',
          },
        },
        contracts: {
          orderBy: {
            createdAt: 'desc',
          },
        },
        invoices: {
          orderBy: {
            createdAt: 'desc',
          },
        },
      },
    });

    if (!deal) {
      throw new AppError(404, 'الصفقة غير موجودة - Deal not found');
    }

    return deal;
  }

  async update(id: string, data: UpdateDealData, userId: string) {
    const existing = await prisma.deal.findUnique({ where: { id } });

    if (!existing) {
      throw new AppError(404, 'الصفقة غير موجودة - Deal not found');
    }

    const deal = await prisma.deal.update({
      where: { id },
      data: {
        name: data.name,
        contactId: data.contactId,
        stage: data.stage,
        estimatedValue: data.estimatedValue,
        actualValue: data.actualValue,
        probability: data.probability,
        expectedCloseDate: data.expectedCloseDate,
        actualCloseDate: data.actualCloseDate,
        wonReason: data.wonReason,
        lostReason: data.lostReason,
        status: data.status,
      },
      include: {
        contact: true,
        owner: true,
        pipeline: true,
      },
    });

    await AuditLogger.log({
      entityType: 'DEAL',
      entityId: deal.id,
      action: 'UPDATE',
      userId,
      changes: {
        before: existing,
        after: deal,
      },
    });

    return deal;
  }

  async updateStage(id: string, stage: string, userId: string) {
    const deal = await prisma.deal.update({
      where: { id },
      data: { stage },
      include: {
        contact: true,
        owner: true,
      },
    });

    await AuditLogger.log({
      entityType: 'DEAL',
      entityId: deal.id,
      action: 'STAGE_CHANGE',
      userId,
      changes: { stage },
    });

    // Create notification
    await prisma.notification.create({
      data: {
        userId: deal.ownerId,
        type: 'DEAL_STAGE_CHANGED',
        title: 'تغيير مرحلة الصفقة - Deal stage changed',
        message: `تم تغيير مرحلة الصفقة "${deal.name}" إلى "${stage}"`,
        entityType: 'DEAL',
        entityId: deal.id,
      },
    });

    return deal;
  }

  async win(id: string, actualValue: number, wonReason: string, userId: string) {
    const deal = await prisma.deal.update({
      where: { id },
      data: {
        status: 'WON',
        stage: 'WON',
        actualValue,
        wonReason,
        actualCloseDate: new Date(),
      },
      include: {
        contact: true,
        owner: true,
      },
    });

    await AuditLogger.log({
      entityType: 'DEAL',
      entityId: deal.id,
      action: 'WIN',
      userId,
      changes: {
        status: 'WON',
        actualValue,
        wonReason,
      },
    });

    // Create notification
    await prisma.notification.create({
      data: {
        userId: deal.ownerId,
        type: 'DEAL_WON',
        title: '🎉 صفقة رابحة - Deal Won!',
        message: `تم الفوز بالصفقة "${deal.name}" بقيمة ${actualValue} ريال`,
        entityType: 'DEAL',
        entityId: deal.id,
      },
    });

    return deal;
  }

  async lose(id: string, lostReason: string, userId: string) {
    const deal = await prisma.deal.update({
      where: { id },
      data: {
        status: 'LOST',
        stage: 'LOST',
        lostReason,
        actualCloseDate: new Date(),
      },
      include: {
        contact: true,
        owner: true,
      },
    });

    await AuditLogger.log({
      entityType: 'DEAL',
      entityId: deal.id,
      action: 'LOSE',
      userId,
      changes: {
        status: 'LOST',
        lostReason,
      },
    });

    return deal;
  }

  async getHistory(id: string) {
    return AuditLogger.getEntityHistory('DEAL', id);
  }

  private async generateDealNumber(): Promise<string> {
    const year = new Date().getFullYear();
    const prefix = `DEAL-${year}-`;
    
    const lastDeal = await prisma.deal.findFirst({
      where: {
        dealNumber: {
          startsWith: prefix,
        },
      },
      orderBy: {
        createdAt: 'desc',
      },
      select: {
        dealNumber: true,
      },
    });

    let nextNumber = 1;
    if (lastDeal) {
      const lastNumber = parseInt(lastDeal.dealNumber.split('-')[2]);
      nextNumber = lastNumber + 1;
    }

    return `${prefix}${nextNumber.toString().padStart(6, '0')}`;
  }
}

export const dealsService = new DealsService();

