import prisma from '../lib/prisma';
import path from 'path';
import fs from 'fs';
import { pipeline } from 'stream/promises';
import { UPLOAD_DIR } from '../lib/uploadPath';
import { CreatePropertyInput, UpdatePropertyInput } from '../validators/property.validator';

export async function listProperties() {
  return prisma.property.findMany({
    include: { images: true, plans: true, documents: true },
    orderBy: { createdAt: 'desc' },
  });
}

export async function getPropertyById(id: number) {
  return prisma.property.findUnique({
    where: { id },
    include: { images: true, plans: true, documents: true },
  });
}

export async function createProperty(data: CreatePropertyInput) {
  const property = await prisma.property.create({
    data: data as any,
  });

  return prisma.property.findUnique({
    where: { id: property.id },
    include: { images: true, plans: true, documents: true },
  });
}

export async function updateProperty(id: number, data: UpdatePropertyInput) {
  const updateData: any = {};
  if (data.title !== undefined) {
    updateData.title = data.title;
    updateData.slug = data.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
  }
  if (data.description !== undefined) updateData.description = data.description;
  if (data.price !== undefined) updateData.price = data.price;
  if (data.status !== undefined) updateData.status = data.status;
  if (data.type !== undefined) updateData.type = data.type;
  if (data.address !== undefined) updateData.address = data.address;
  if (data.city !== undefined) updateData.city = data.city;
  if (data.province !== undefined) updateData.province = data.province;
  if (data.area !== undefined) updateData.area = data.area;
  if (data.bedrooms !== undefined) updateData.bedrooms = data.bedrooms;
  if (data.bathrooms !== undefined) updateData.bathrooms = data.bathrooms;
  if (data.parkingSpaces !== undefined) updateData.parkingSpaces = data.parkingSpaces;

  if (Object.keys(updateData).length > 0) {
    await prisma.property.update({
      where: { id },
      data: updateData,
    });
  }

  return prisma.property.findUnique({
    where: { id },
    include: { images: true, plans: true, documents: true },
  });
}

export async function deleteProperty(id: number) {
  await prisma.property.delete({ where: { id } });
  return { message: 'Propiedad eliminada' };
}

// ─── Images ───────────────────────────

export async function uploadPropertyImages(propertyId: number, files: AsyncIterable<any>) {
  const uploadedImages = [];
  for await (const part of files) {
    if (part.type === 'file') {
      const filename = `${Date.now()}-${part.filename}`;
      const savePath = path.join(UPLOAD_DIR, filename);
      await pipeline(part.file, fs.createWriteStream(savePath));
      try {
        const imageUrl = `https://fmetalconstructora.nitronsystem.com/uploads/${filename}`;
        const image = await prisma.propertyImage.create({
          data: { url: imageUrl, filename, propertyId } as any,
        });
        uploadedImages.push(image);
      } catch (err) {
        fs.unlink(savePath, () => {});
        throw err;
      }
    }
  }
  return uploadedImages;
}

export async function uploadPropertyPlans(propertyId: number, files: AsyncIterable<any>) {
  const uploadedPlans = [];
  for await (const part of files) {
    if (part.type === 'file') {
      if (part.mimetype !== 'application/pdf') continue;
      const filename = `${Date.now()}-${part.filename}`;
      const savePath = path.join(UPLOAD_DIR, filename);
      await pipeline(part.file, fs.createWriteStream(savePath));
      try {
        const planUrl = `https://fmetalconstructora.nitronsystem.com/uploads/${filename}`;
        const plan = await prisma.propertyPlan.create({
          data: {
            title: part.fieldname || 'Plan',
            url: planUrl,
            filename,
            propertyId,
          } as any,
        });
        uploadedPlans.push(plan);
      } catch (err) {
        fs.unlink(savePath, () => {});
        throw err;
      }
    }
  }
  return uploadedPlans;
}

export async function deletePropertyImage(imageId: number) {
  const image = await prisma.propertyImage.findUnique({ where: { id: imageId } });
  if (!image) {
    const err: any = new Error('Imagen no encontrada');
    err.statusCode = 404;
    throw err;
  }
  const filename = image.url.split('/').pop();
  if (filename) {
    const filePath = path.join(UPLOAD_DIR, filename);
    if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
  }
  await prisma.propertyImage.delete({ where: { id: imageId } });
  return { message: 'Imagen eliminada' };
}

export async function deletePropertyPlan(planId: number) {
  const plan = await prisma.propertyPlan.findUnique({ where: { id: planId } });
  if (!plan) {
    const err: any = new Error('Plano no encontrado');
    err.statusCode = 404;
    throw err;
  }
  const filename = plan.url.split('/').pop();
  if (filename) {
    const filePath = path.join(UPLOAD_DIR, filename);
    if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
  }
  await prisma.propertyPlan.delete({ where: { id: planId } });
  return { message: 'Plano eliminado' };
}

// ─── Documents ──────────────────────────────────────────

export async function uploadPropertyDocument(propertyId: number, docType: string, category: string, file: any) {
  const filename = `${Date.now()}-${file.filename}`;
  const savePath = path.join(UPLOAD_DIR, filename);
  await pipeline(file.file, fs.createWriteStream(savePath));

  const fileUrl = `https://fmetalconstructora.nitronsystem.com/uploads/${filename}`;

  return prisma.propertyDocument.create({
    data: {
      propertyId,
      type: docType as any,
      name: category,
      filename: file.filename,
      url: fileUrl,
      status: 'UPLOADED' as any,
    } as any,
  });
}

export async function verifyPropertyDocument(documentId: number) {
  return prisma.propertyDocument.update({
    where: { id: documentId },
    data: { status: 'VERIFIED' as any },
  });
}

export async function revokePropertyDocument(documentId: number) {
  return prisma.propertyDocument.update({
    where: { id: documentId },
    data: { status: 'PENDING' as any },
  });
}

export async function deletePropertyDocument(documentId: number) {
  const doc = await prisma.propertyDocument.findUnique({ where: { id: documentId } });
  if (!doc) {
    const err: any = new Error('Documento no encontrado');
    err.statusCode = 404;
    throw err;
  }
  if (doc.url) {
    const filename = doc.url.split('/').pop();
    if (filename) {
      const filePath = path.join(UPLOAD_DIR, filename);
      if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
    }
  }
  await prisma.propertyDocument.delete({ where: { id: documentId } });
  return { message: 'Documento eliminado' };
}