import { NextResponse } from 'next/server';
import prisma from '../../../../lib/prisma';
import { getServerSession } from "next-auth/next";
import { authOptions } from "../../auth/[...nextauth]/route";

const PREFIXES: Record<string, string> = {
  QUOTE: 'ANG', ORDER_CONFIRMATION: 'AB', DELIVERY_NOTE: 'LS', INVOICE: 'RE', CREDIT_NOTE: 'RK'
};
const NUMBER_FIELDS: Record<string, string> = {
  QUOTE: 'nextQuoteNumber', ORDER_CONFIRMATION: 'nextOrderNumber',
  DELIVERY_NOTE: 'nextDeliveryNumber', INVOICE: 'nextInvoiceNumber', CREDIT_NOTE: 'nextCreditNoteNumber'
};

async function generateNumber(type: string) {
  const settings = await prisma.systemSettings.findFirst();
  if (!settings) throw new Error('SystemSettings not found');
  const year = new Date().getFullYear();
  const prefix = PREFIXES[type] || 'DOC';
  const field = NUMBER_FIELDS[type];
  const num = (settings as any)[field] || 1;
  await prisma.systemSettings.update({ where: { id: settings.id }, data: { [field]: num + 1 } });
  return `${prefix}-${year}-${num.toString().padStart(4, '0')}`;
}

// Set status to ARCHIVED while preserving original status in previousStatus
async function archiveDoc(docId: number) {
  const doc = await prisma.salesDocument.findUnique({ where: { id: docId }, select: { status: true } });
  if (!doc || doc.status === 'ARCHIVED' || doc.status === 'CANCELLED') return;
  await prisma.salesDocument.update({
    where: { id: docId },
    data: { previousStatus: doc.status, status: 'ARCHIVED' }
  });
}

// Walk the chain back via sourceDocumentId and collect all related doc IDs
async function getChainIds(docId: number): Promise<number[]> {
  const ids: number[] = [];
  let currentId: number | null = docId;
  while (currentId) {
    const doc = await prisma.salesDocument.findUnique({ where: { id: currentId }, select: { sourceDocumentId: true } });
    if (doc?.sourceDocumentId) {
      ids.push(doc.sourceDocumentId);
      currentId = doc.sourceDocumentId;
    } else {
      currentId = null;
    }
  }
  return ids;
}

export async function GET(request: Request, context: { params: Promise<{ id: string }> }) {
  try {
    const { id } = await context.params;
    const doc = await prisma.salesDocument.findUnique({
      where: { id: parseInt(id) },
      include: {
        customer: true,
        items: { include: { product: true } },
        createdBy: { select: { firstName: true, lastName: true } }
      }
    });
    if (!doc) return NextResponse.json({ error: 'Nicht gefunden' }, { status: 404 });
    return NextResponse.json(doc);
  } catch (error) {
    return NextResponse.json({ error: 'Ladefehler' }, { status: 500 });
  }
}

export async function PUT(request: Request, context: { params: Promise<{ id: string }> }) {
  const session = await getServerSession(authOptions);
  const perms = (session?.user as any)?.permissions || [];
  if (!perms.includes('SALES_MANAGE')) return NextResponse.json({ error: 'Keine Berechtigung' }, { status: 403 });

  try {
    const { id } = await context.params;
    const body = await request.json();
    const docId = parseInt(id);

    // Handle signature (not for invoices/credit notes)
    if (body.signatureData) {
      const doc = await prisma.salesDocument.findUnique({ where: { id: docId } });
      if (doc?.type === 'INVOICE' || doc?.type === 'CREDIT_NOTE') {
        return NextResponse.json({ error: 'Kann nicht unterschrieben werden' }, { status: 400 });
      }
      const updated = await prisma.salesDocument.update({
        where: { id: docId },
        data: { signatureData: body.signatureData, signedAt: new Date(), status: 'ACCEPTED' }
      });
      return NextResponse.json(updated);
    }

    // Handle "create follow-up document" action
    if (body.action === 'CREATE_FOLLOWUP') {
      const doc = await prisma.salesDocument.findUnique({ where: { id: docId }, include: { items: true } });
      if (!doc) return NextResponse.json({ error: 'Not found' }, { status: 404 });

      let newType = '';
      if (doc.type === 'ORDER_CONFIRMATION') newType = 'DELIVERY_NOTE';
      else if (doc.type === 'DELIVERY_NOTE') newType = 'INVOICE';
      else if (doc.type === 'INVOICE') newType = 'CREDIT_NOTE';
      else return NextResponse.json({ error: 'Kein Folgebeleg möglich' }, { status: 400 });

      const number = await generateNumber(newType);
      const followUp = await prisma.salesDocument.create({
        data: {
          type: newType as any,
          number,
          customerId: doc.customerId,
          createdById: (session?.user as any)?.id || null,
          sourceDocumentId: doc.id,
          subtotal: doc.subtotal, taxAmount: doc.taxAmount, total: doc.total,
          notes: newType === 'CREDIT_NOTE' ? `Rechnungskorrektur zu ${doc.number}` : doc.notes,
          items: {
            create: doc.items.map(i => ({
              description: i.description, quantity: i.quantity, unitPrice: i.unitPrice,
              taxRate: i.taxRate, total: i.total, productId: i.productId
            }))
          }
        },
        include: { items: true }
      });

      // CREDIT_NOTE → cancel the original invoice
      if (newType === 'CREDIT_NOTE') {
        await prisma.salesDocument.update({
          where: { id: doc.id },
          data: { previousStatus: doc.status, status: 'CANCELLED' }
        });
      } else {
        // Archive the source document
        await archiveDoc(doc.id);
      }

      // If creating an INVOICE → also archive all earlier docs in the chain
      if (newType === 'INVOICE') {
        const chainIds = await getChainIds(followUp.id);
        for (const cid of chainIds) { await archiveDoc(cid); }
      }

      return NextResponse.json(followUp, { status: 201 });
    }

    // Handle status changes
    if (body.status) {
      const doc = await prisma.salesDocument.findUnique({
        where: { id: docId },
        include: { items: { include: { product: true } } }
      });
      if (!doc) return NextResponse.json({ error: 'Not found' }, { status: 404 });

      // QUOTE accepted → reserve stock + auto-create AB (SENT) + archive quote
      if (doc.type === 'QUOTE' && body.status === 'ACCEPTED') {
        for (const item of doc.items) {
          if (item.productId && item.product?.trackStock) {
            await prisma.product.update({
              where: { id: item.productId },
              data: { reservedStock: { increment: Math.ceil(item.quantity) } }
            });
          }
        }

        // Auto-create AB with status SENT
        const abNumber = await generateNumber('ORDER_CONFIRMATION');
        const ab = await prisma.salesDocument.create({
          data: {
            type: 'ORDER_CONFIRMATION',
            number: abNumber,
            status: 'SENT',
            customerId: doc.customerId,
            createdById: (session?.user as any)?.id || null,
            sourceDocumentId: doc.id,
            subtotal: doc.subtotal, taxAmount: doc.taxAmount, total: doc.total,
            notes: doc.notes,
            items: {
              create: doc.items.map(i => ({
                description: i.description, quantity: i.quantity, unitPrice: i.unitPrice,
                taxRate: i.taxRate, total: i.total, productId: i.productId
              }))
            }
          }
        });

        // Archive the quote (preserving ACCEPTED as previousStatus)
        await prisma.salesDocument.update({
          where: { id: docId },
          data: { previousStatus: 'ACCEPTED', status: 'ARCHIVED' }
        });

        return NextResponse.json({ ...doc, status: 'ARCHIVED', followUpId: ab.id, followUpNumber: ab.number });
      }

      // DELIVERY_NOTE delivered → reduce stock
      if (doc.type === 'DELIVERY_NOTE' && body.status === 'DELIVERED') {
        for (const item of doc.items) {
          if (item.productId && item.product?.trackStock) {
            await prisma.product.update({
              where: { id: item.productId },
              data: {
                stock: { decrement: Math.ceil(item.quantity) },
                reservedStock: { decrement: Math.ceil(item.quantity) }
              }
            });
          }
        }
      }

      // INVOICE paid → mark as paid then archive
      if (doc.type === 'INVOICE' && body.status === 'PAID') {
        await prisma.salesDocument.update({
          where: { id: docId },
          data: { previousStatus: 'PAID', status: 'ARCHIVED' }
        });
        return NextResponse.json({ ...doc, status: 'ARCHIVED', previousStatus: 'PAID' });
      }
    }

    const updated = await prisma.salesDocument.update({
      where: { id: docId },
      data: {
        status: body.status || undefined,
        notes: body.notes !== undefined ? body.notes : undefined,
      },
      include: { items: true, customer: true }
    });

    return NextResponse.json(updated);
  } catch (error) {
    console.error(error);
    return NextResponse.json({ error: 'Fehler' }, { status: 500 });
  }
}
