import { ListingStatus, Role, UserStatus } from '@prisma/client';
import { NextResponse } from 'next/server';
import { prisma } from '../../../../lib/prisma';
import { requireAuth } from '../../../../lib/jwt';
import { parsePrice, normalizeCalendarUrls } from '../route'; // reuse helpers

const MAX_IMAGES = 6;
const MAX_IMAGE_BYTES = 5 * 1024 * 1024;

export async function GET(_req: Request, { params }: { params: { id: string } }) {
  try {
    const auth = await requireAuth(_req);
    const listing = await prisma.listing.findFirst({
      where: { id: params.id, ownerId: auth.userId, removedAt: null },
      include: {
        translations: true,
        images: { orderBy: { order: 'asc' }, select: { id: true, altText: true, order: true, isCover: true, size: true, url: true, mimeType: true } },
      },
    });

    if (!listing) {
      return NextResponse.json({ error: 'Not found' }, { status: 404 });
    }

    return NextResponse.json({ listing });
  } catch (err: any) {
    const status = err?.message === 'Unauthorized' ? 401 : 500;
    return NextResponse.json({ error: 'Failed to load listing' }, { status });
  }
}

export async function PUT(req: Request, { params }: { params: { id: string } }) {
  try {
    const auth = await requireAuth(req);
    const user = await prisma.user.findUnique({ where: { id: auth.userId } });
    if (!user || !user.emailVerifiedAt || !user.approvedAt || user.status !== UserStatus.ACTIVE) {
      return NextResponse.json({ error: 'User not permitted to edit listings' }, { status: 403 });
    }

    const existing = await prisma.listing.findFirst({
      where: { id: params.id, ownerId: auth.userId, removedAt: null },
      include: { translations: true, images: true },
    });

    if (!existing) {
      return NextResponse.json({ error: 'Not found' }, { status: 404 });
    }

    const body = await req.json();
    const saveDraft = Boolean(body.saveDraft);

    const baseSlug = String(body.slug ?? existing.translations[0]?.slug ?? '').trim().toLowerCase();
    if (!baseSlug) {
      return NextResponse.json({ error: 'Missing slug' }, { status: 400 });
    }

    const country = String(body.country ?? existing.country ?? '').trim();
    const region = String(body.region ?? existing.region ?? '').trim();
    const city = String(body.city ?? existing.city ?? '').trim();
    const streetAddress = String(body.streetAddress ?? existing.streetAddress ?? '').trim();
    const contactName = String(body.contactName ?? existing.contactName ?? '').trim();
    const contactEmail = String(body.contactEmail ?? existing.contactEmail ?? '').trim();

    const maxGuests = body.maxGuests === undefined || body.maxGuests === null || body.maxGuests === '' ? existing.maxGuests : Number(body.maxGuests);
    const bedrooms = body.bedrooms === undefined || body.bedrooms === null || body.bedrooms === '' ? existing.bedrooms : Number(body.bedrooms);
    const beds = body.beds === undefined || body.beds === null || body.beds === '' ? existing.beds : Number(body.beds);
    const bathrooms = body.bathrooms === undefined || body.bathrooms === null || body.bathrooms === '' ? existing.bathrooms : Number(body.bathrooms);
    const priceWeekdayEuros = body.priceWeekdayEuros === undefined ? existing.priceWeekdayEuros : parsePrice(body.priceWeekdayEuros);
    const priceWeekendEuros = body.priceWeekendEuros === undefined ? existing.priceWeekendEuros : parsePrice(body.priceWeekendEuros);
    const calendarUrls = normalizeCalendarUrls(body.calendarUrls ?? existing.calendarUrls);

    const translationsInputRaw = Array.isArray(body.translations) ? body.translations : null;
    type TranslationInput = { locale: string; title: string; description: string; teaser: string | null; slug: string };
    const translationsInput: TranslationInput[] =
      translationsInputRaw?.map((item: any) => ({
        locale: String(item.locale ?? '').toLowerCase(),
        title: typeof item.title === 'string' ? item.title.trim() : '',
        description: typeof item.description === 'string' ? item.description.trim() : '',
        teaser: typeof item.teaser === 'string' ? item.teaser.trim() : null,
        slug: String(item.slug ?? baseSlug).trim().toLowerCase(),
      })) || [];

    const fallbackTranslationTitle = typeof body.title === 'string' ? body.title.trim() : existing.translations[0]?.title ?? '';
    const fallbackTranslationDescription = typeof body.description === 'string' ? body.description.trim() : existing.translations[0]?.description ?? '';
    const fallbackTranslationTeaser = typeof body.teaser === 'string' ? body.teaser.trim() : existing.translations[0]?.teaser ?? null;
    const fallbackLocale = String(body.locale ?? existing.translations[0]?.locale ?? 'en').toLowerCase();

    if (translationsInput.length === 0 && (fallbackTranslationTitle || saveDraft) && (fallbackTranslationDescription || saveDraft)) {
      translationsInput.push({
        locale: fallbackLocale,
        title: fallbackTranslationTitle ?? '',
        description: fallbackTranslationDescription ?? '',
        teaser: fallbackTranslationTeaser,
        slug: baseSlug,
      });
    }

    const imagesBody = Array.isArray(body.images) ? body.images.slice(0, MAX_IMAGES) : null;

    if (!saveDraft) {
      const missing: string[] = [];
      if (!country) missing.push('country');
      if (!region) missing.push('region');
      if (!city) missing.push('city');
      if (!contactEmail) missing.push('contactEmail');
      if (!contactName) missing.push('contactName');
      if (!maxGuests) missing.push('maxGuests');
      if (!bedrooms && bedrooms !== 0) missing.push('bedrooms');
      if (!beds) missing.push('beds');
      if (!bathrooms) missing.push('bathrooms');
      if (!translationsInput.length && !existing.translations.length) missing.push('translations');
      const hasImagesIncoming = imagesBody && imagesBody.length > 0;
      if (!hasImagesIncoming && existing.images.length === 0) missing.push('images');
      if (missing.length) {
        return NextResponse.json({ error: `Missing required fields: ${missing.join(', ')}` }, { status: 400 });
      }
    }

    let status = existing.status;
    const autoApprove = !saveDraft && (process.env.AUTO_APPROVE_LISTINGS === 'true' || auth.role === Role.ADMIN);
    if (saveDraft) {
      status = ListingStatus.DRAFT;
    } else if (existing.status === ListingStatus.PUBLISHED) {
      status = ListingStatus.PUBLISHED;
    } else {
      status = autoApprove ? ListingStatus.PUBLISHED : ListingStatus.PENDING;
    }

    const parsedImages: {
      data?: Buffer;
      mimeType?: string | null;
      size?: number | null;
      url?: string | null;
      altText?: string | null;
      order: number;
      isCover: boolean;
    }[] = [];

    if (imagesBody) {
      const coverImageIndex = Math.min(Math.max(Number(body.coverImageIndex ?? 1), 1), imagesBody.length || 1);

      for (let idx = 0; idx < imagesBody.length; idx += 1) {
        const img = imagesBody[idx];
        const altText = typeof img.altText === 'string' && img.altText.trim() ? img.altText.trim() : null;
        const rawMime = typeof img.mimeType === 'string' ? img.mimeType : null;
        const rawData = typeof img.data === 'string' ? img.data : null;
        const rawUrl = typeof img.url === 'string' && img.url.trim() ? img.url.trim() : null;
        let mimeType = rawMime;
        let buffer: Buffer | null = null;

        if (rawData) {
          const dataUrlMatch = rawData.match(/^data:(.*?);base64,(.*)$/);
          if (dataUrlMatch) {
            mimeType = mimeType || dataUrlMatch[1] || null;
            buffer = Buffer.from(dataUrlMatch[2], 'base64');
          } else {
            buffer = Buffer.from(rawData, 'base64');
          }
        }

        const size = buffer ? buffer.length : null;
        if (size && size > MAX_IMAGE_BYTES) {
          return NextResponse.json({ error: `Image ${idx + 1} is too large (max ${Math.floor(MAX_IMAGE_BYTES / 1024 / 1024)}MB)` }, { status: 400 });
        }

        if (!buffer && !rawUrl) {
          continue;
        }

        parsedImages.push({
          data: buffer ?? undefined,
          mimeType: mimeType || 'image/jpeg',
          size,
          url: buffer ? null : rawUrl,
          altText,
          order: idx + 1,
          isCover: coverImageIndex === idx + 1,
        });
      }

      if (parsedImages.length && !parsedImages.some((img) => img.isCover)) {
        parsedImages[0].isCover = true;
      }
    }

    const incomingEvChargingOnSite =
      body.evChargingOnSite === undefined ? existing.evChargingOnSite : Boolean(body.evChargingOnSite);
    const incomingEvChargingAvailable =
      body.evChargingAvailable === undefined ? existing.evChargingAvailable : Boolean(body.evChargingAvailable);
    const evChargingAvailable = incomingEvChargingOnSite ? true : incomingEvChargingAvailable;
    const evChargingOnSite = evChargingAvailable ? incomingEvChargingOnSite : false;

    const updateData: any = {
      status,
      approvedAt: status === ListingStatus.PUBLISHED ? existing.approvedAt ?? new Date() : null,
      approvedById: status === ListingStatus.PUBLISHED && auth.role === Role.ADMIN ? auth.userId : existing.approvedById,
      country: country || null,
      region: region || null,
      city: city || null,
      streetAddress: streetAddress || null,
      addressNote: body.addressNote ?? existing.addressNote ?? null,
      latitude: body.latitude !== undefined && body.latitude !== null && body.latitude !== '' ? Number(body.latitude) : existing.latitude,
      longitude: body.longitude !== undefined && body.longitude !== null && body.longitude !== '' ? Number(body.longitude) : existing.longitude,
      maxGuests,
      bedrooms,
      beds,
      bathrooms,
      hasSauna: body.hasSauna === undefined ? existing.hasSauna : Boolean(body.hasSauna),
      hasFireplace: body.hasFireplace === undefined ? existing.hasFireplace : Boolean(body.hasFireplace),
      hasWifi: body.hasWifi === undefined ? existing.hasWifi : Boolean(body.hasWifi),
      petsAllowed: body.petsAllowed === undefined ? existing.petsAllowed : Boolean(body.petsAllowed),
      byTheLake: body.byTheLake === undefined ? existing.byTheLake : Boolean(body.byTheLake),
      hasAirConditioning: body.hasAirConditioning === undefined ? existing.hasAirConditioning : Boolean(body.hasAirConditioning),
      hasKitchen: body.hasKitchen === undefined ? existing.hasKitchen : Boolean(body.hasKitchen),
      hasDishwasher: body.hasDishwasher === undefined ? existing.hasDishwasher : Boolean(body.hasDishwasher),
      hasWashingMachine: body.hasWashingMachine === undefined ? existing.hasWashingMachine : Boolean(body.hasWashingMachine),
      hasBarbecue: body.hasBarbecue === undefined ? existing.hasBarbecue : Boolean(body.hasBarbecue),
      hasMicrowave: body.hasMicrowave === undefined ? existing.hasMicrowave : Boolean(body.hasMicrowave),
      hasFreeParking: body.hasFreeParking === undefined ? existing.hasFreeParking : Boolean(body.hasFreeParking),
      hasSkiPass: body.hasSkiPass === undefined ? existing.hasSkiPass : Boolean(body.hasSkiPass),
      evChargingAvailable,
      evChargingOnSite,
      wheelchairAccessible:
        body.wheelchairAccessible === undefined ? existing.wheelchairAccessible : Boolean(body.wheelchairAccessible),
      priceWeekdayEuros,
      priceWeekendEuros,
      calendarUrls,
      contactName: contactName || null,
      contactEmail: contactEmail || null,
      contactPhone: body.contactPhone ?? existing.contactPhone ?? null,
      externalUrl: body.externalUrl ?? existing.externalUrl ?? null,
      published: status === ListingStatus.PUBLISHED,
    };

    const tx: any[] = [];

    if (translationsInput && translationsInput.length) {
      tx.push(
        prisma.listingTranslation.deleteMany({ where: { listingId: existing.id } }),
        prisma.listingTranslation.createMany({
          data: translationsInput.map((t) => ({
            listingId: existing.id,
            locale: t.locale,
            slug: t.slug || baseSlug,
            title: t.title,
            description: t.description,
            teaser: t.teaser ?? null,
          })),
        }),
      );
    }

    if (parsedImages && parsedImages.length) {
      tx.push(prisma.listingImage.deleteMany({ where: { listingId: existing.id } }));
      tx.push(
        prisma.listingImage.createMany({
          data: parsedImages.map((img) => ({
            listingId: existing.id,
            mimeType: img.mimeType || 'image/jpeg',
            size: img.size ?? null,
            url: img.url ?? null,
            altText: img.altText ?? null,
            order: img.order,
            isCover: img.isCover,
            data: img.data ?? null,
          })),
        }),
      );
    }

    tx.unshift(prisma.listing.update({ where: { id: existing.id }, data: updateData }));

    await prisma.$transaction(tx);

    const updated = await prisma.listing.findUnique({
      where: { id: existing.id },
      include: {
        translations: true,
        images: { orderBy: { order: 'asc' }, select: { id: true, url: true, altText: true, order: true, isCover: true, size: true, mimeType: true } },
      },
    });

    return NextResponse.json({ ok: true, listing: updated });
  } catch (error: any) {
    console.error('Update listing error', error);
    const message = error?.code === 'P2002' ? 'Slug already exists for this locale' : 'Failed to update listing';
    const status = error?.message === 'Unauthorized' ? 401 : 400;
    return NextResponse.json({ error: message }, { status });
  }
}
