import prisma from '../../config/database';
import { Prisma } from '@prisma/client';
import { AppError } from '../../shared/middleware/errorHandler';
import { contactsService } from '../contacts/contacts.service';

interface SupplierFilters {
  search?: string;
  status?: string;
  rating?: number;
  category?: string;
}

interface SupplierContactData {
  name?: string;
  nameAr?: string;
  email?: string;
  phone?: string;
  mobile?: string;
  website?: string;
  companyName?: string;
  companyNameAr?: string;
  taxNumber?: string;
  commercialRegister?: string;
  address?: string;
  city?: string;
  country?: string;
  postalCode?: string;
  categories?: string[];
  tags?: string[];
  source?: string;
  rating?: number;
  status?: string;
  customFields?: any;
  createdById?: string;
}

class SuppliersService {
  private supplierCategoryNames = ['Supplier', 'Suppliers'];

  private isSupplierSystemCategory(category: any) {
    return (
      this.supplierCategoryNames.includes(category?.name) ||
      Boolean(category?.nameAr && String(category.nameAr).includes('مورد'))
    );
  }

  private getSupplierCategoryLabels(supplier: any): string[] {
    const customFields = supplier.customFields || {};

    if (Array.isArray(customFields.supplierCategories)) {
      return customFields.supplierCategories
        .map((category: any) => String(category || '').trim())
        .filter(Boolean);
    }

    if (customFields.supplierCategory) return [String(customFields.supplierCategory)];

    return (supplier.categories || [])
      .filter((category: any) => !this.isSupplierSystemCategory(category))
      .map((category: any) => category.nameAr ? `${category.name} (${category.nameAr})` : category.name)
      .filter(Boolean);
  }

  private async ensureSupplierCategory() {
    const existing = await prisma.contactCategory.findFirst({
      where: {
        isActive: true,
        OR: [
          { name: { in: this.supplierCategoryNames } },
          { nameAr: { contains: 'مورد' } },
        ],
      },
    });

    if (existing) return existing;

    return prisma.contactCategory.create({
      data: {
        name: 'Supplier',
        nameAr: 'مورّد',
        description: 'Supplier / vendor records managed from Supplier Management module',
      },
    });
  }

  private supplierCondition(): Prisma.ContactWhereInput {
    return {
      OR: [
        { type: 'SUPPLIER' },
        {
          categories: {
            some: {
              OR: [
                { name: { in: this.supplierCategoryNames } },
                { nameAr: { contains: 'مورد' } },
              ],
            },
          },
        },
      ],
    };
  }

  private buildWhere(filters: SupplierFilters = {}): Prisma.ContactWhereInput {
    const andConditions: Prisma.ContactWhereInput[] = [
      { archivedAt: null },
      this.supplierCondition(),
    ];

    if (filters.search) {
      andConditions.push({
        OR: [
          { name: { contains: filters.search, mode: 'insensitive' } },
          { nameAr: { contains: filters.search, mode: 'insensitive' } },
          { email: { contains: filters.search, mode: 'insensitive' } },
          { phone: { contains: filters.search } },
          { mobile: { contains: filters.search } },
          { companyName: { contains: filters.search, mode: 'insensitive' } },
          { companyNameAr: { contains: filters.search, mode: 'insensitive' } },
          { taxNumber: { contains: filters.search, mode: 'insensitive' } },
          { commercialRegister: { contains: filters.search, mode: 'insensitive' } },
        ],
      });
    }

    if (filters.status) andConditions.push({ status: filters.status });
    if (filters.rating !== undefined) andConditions.push({ rating: filters.rating });
    if (filters.category) {
      andConditions.push({
        OR: [
          {
            customFields: {
              path: ['supplierCategories'],
              array_contains: [filters.category],
            } as any,
          },
          {
            customFields: {
              path: ['supplierCategory'],
              equals: filters.category,
            } as any,
          },
          {
            categories: {
              some: {
                OR: [
                  { name: { equals: filters.category, mode: 'insensitive' } },
                  { nameAr: { equals: filters.category } },
                ],
              },
            },
          },
        ],
      });
    }

    return { AND: andConditions };
  }

  private isSupplierContact(contact: any) {
    return (
      contact.type === 'SUPPLIER' ||
      contact.categories?.some((category: any) => this.isSupplierSystemCategory(category))
    );
  }

  async findAll(filters: SupplierFilters, page: number = 1, pageSize: number = 20) {
    const skip = (page - 1) * pageSize;
    const where = this.buildWhere(filters);

    const [total, suppliers] = await Promise.all([
      prisma.contact.count({ where }),
      prisma.contact.findMany({
        where,
        skip,
        take: pageSize,
        include: {
          categories: true,
          parent: { select: { id: true, name: true, type: true } },
          createdBy: { select: { id: true, email: true, username: true } },
        },
        orderBy: { createdAt: 'desc' },
      }),
    ]);

    return { suppliers, total, page, pageSize, totalPages: Math.ceil(total / pageSize) };
  }

  async findById(id: string) {
    const supplier = await prisma.contact.findUnique({
      where: { id },
      include: {
        categories: true,
        parent: true,
        createdBy: { select: { id: true, email: true, username: true } },
      },
    });

    if (!supplier || supplier.archivedAt || !this.isSupplierContact(supplier)) {
      throw new AppError(404, 'المورد غير موجود - Supplier not found');
    }

    return supplier;
  }

  async create(data: SupplierContactData, userId: string) {
    const supplierCategory = await this.ensureSupplierCategory();
    const categories = [supplierCategory.id];

    return contactsService.create(
      {
        ...data,
        type: 'SUPPLIER',
        name: data.name || data.companyName || 'Supplier',
        companyName: data.companyName || data.name,
        country: data.country || 'Syria',
        source: data.source || 'SUPPLIER_MODULE',
        categories,
        createdById: data.createdById || userId,
      },
      userId
    );
  }

  async update(id: string, data: SupplierContactData, userId: string) {
    const existing = await this.findById(id);
    const supplierCategory = await this.ensureSupplierCategory();
    const categories = [supplierCategory.id];

    return contactsService.update(
      id,
      {
        ...data,
        type: 'SUPPLIER',
        name: data.name || data.companyName || existing.name,
        companyName: data.companyName || data.name || existing.companyName || undefined,
        categories,
      },
      userId
    );
  }

  async archive(id: string, userId: string, reason?: string) {
    await this.findById(id);
    return contactsService.archive(id, userId, reason || 'Archived from Supplier Management');
  }

  async getStats() {
    const [total, active, inactive, blocked] = await Promise.all([
      prisma.contact.count({ where: this.buildWhere() }),
      prisma.contact.count({ where: this.buildWhere({ status: 'ACTIVE' }) }),
      prisma.contact.count({ where: this.buildWhere({ status: 'INACTIVE' }) }),
      prisma.contact.count({ where: this.buildWhere({ status: 'BLOCKED' }) }),
    ]);
    return { total, active, inactive, blocked };
  }

  async export(filters: SupplierFilters): Promise<Buffer> {
    const xlsx = require('xlsx');
    const suppliers = await prisma.contact.findMany({
      where: this.buildWhere(filters),
      include: {
        categories: true,
        createdBy: { select: { username: true, email: true } },
      },
      orderBy: { createdAt: 'desc' },
    });

    const exportData = suppliers.map((supplier) => {
      const customFields: any = supplier.customFields || {};
      const categoryNames = this.getSupplierCategoryLabels(supplier).join(', ');

      return {
        'Supplier ID': supplier.uniqueContactId,
        'Supplier Code': customFields.supplierCode || '',
        'Supplier Name': supplier.companyName || supplier.name,
        'Supplier Name (Arabic)': supplier.companyNameAr || supplier.nameAr || '',
        'Contact Person': supplier.name || '',
        'Email': supplier.email || '',
        'Phone': supplier.phone || '',
        'Mobile': supplier.mobile || '',
        'Website': supplier.website || '',
        'Tax Number': supplier.taxNumber || '',
        'Commercial Register': supplier.commercialRegister || '',
        'Categories': categoryNames,
        'Payment Terms': customFields.paymentTerms || '',
        'Bank Name': customFields.bankName || '',
        'Bank Account': customFields.bankAccount || '',
        'Address': supplier.address || '',
        'City': supplier.city || '',
        'Country': supplier.country || '',
        'Status': supplier.status,
        'Rating': supplier.rating || '',
        'Notes': customFields.notes || '',
        'Created By': supplier.createdBy?.username || supplier.createdBy?.email || '',
        'Created At': supplier.createdAt.toISOString(),
      };
    });

    const worksheet = xlsx.utils.json_to_sheet(exportData);
    const workbook = xlsx.utils.book_new();
    xlsx.utils.book_append_sheet(workbook, worksheet, 'Suppliers');
    worksheet['!cols'] = [
      { wch: 16 }, { wch: 18 }, { wch: 28 }, { wch: 28 }, { wch: 24 }, { wch: 30 },
      { wch: 16 }, { wch: 16 }, { wch: 24 }, { wch: 18 }, { wch: 22 }, { wch: 18 },
      { wch: 18 }, { wch: 22 }, { wch: 26 }, { wch: 30 }, { wch: 16 }, { wch: 16 },
      { wch: 12 }, { wch: 12 }, { wch: 30 }, { wch: 18 }, { wch: 24 },
    ];

    return xlsx.write(workbook, { type: 'buffer', bookType: 'xlsx' });
  }
}

export const suppliersService = new SuppliersService();
