/**
 * Real Estate Transaction Detail API
 * GET - Transaction detail with property and full history
 * PUT - Update stage/details with transition validation
 */

import { NextRequest } from "next/server";
import { auth } from "@/lib/auth";
import { prisma } from "@/lib/db";
import { getAuthenticatedEmail } from "@/lib/utils/auth-helpers.util";
import { getEffectiveOwnerId } from "@/lib/utils/organization-data";
import { logger } from "@/lib/logger";
import { ApiResponses } from "@/lib/utils/api-response.util";
import { withRateLimit, rateLimiters } from "@/lib/rate-limiter";
import { getErrorMessage } from "@/lib/errors";
import { withCSRF } from "@/lib/csrf";
const TransactionStage = {
  INQUIRY: "INQUIRY",
  QUALIFIED: "QUALIFIED",
  VIEWING_SCHEDULED: "VIEWING_SCHEDULED",
  VIEWING_COMPLETED: "VIEWING_COMPLETED",
  INTERESTED: "INTERESTED",
  OFFER_MADE: "OFFER_MADE",
  NEGOTIATION: "NEGOTIATION",
  OFFER_ACCEPTED: "OFFER_ACCEPTED",
  DEPOSIT_PAID: "DEPOSIT_PAID",
  CONTRACT_SIGNED: "CONTRACT_SIGNED",
  PAYMENT_PROCESSING: "PAYMENT_PROCESSING",
  TX_COMPLETED: "TX_COMPLETED",
  LOST: "LOST",
} as const;
type TransactionStage =
  (typeof TransactionStage)[keyof typeof TransactionStage];

export const dynamic = "force-dynamic";

// Valid stage transitions (from -> allowed next stages)
const VALID_TRANSITIONS: Record<TransactionStage, TransactionStage[]> = {
  INQUIRY: ["QUALIFIED", "LOST"],
  QUALIFIED: ["VIEWING_SCHEDULED", "LOST"],
  VIEWING_SCHEDULED: ["VIEWING_COMPLETED", "LOST"],
  VIEWING_COMPLETED: ["INTERESTED", "LOST"],
  INTERESTED: ["OFFER_MADE", "LOST"],
  OFFER_MADE: ["NEGOTIATION", "OFFER_ACCEPTED", "LOST"],
  NEGOTIATION: ["OFFER_ACCEPTED", "OFFER_MADE", "LOST"],
  OFFER_ACCEPTED: ["DEPOSIT_PAID", "LOST"],
  DEPOSIT_PAID: ["CONTRACT_SIGNED", "LOST"],
  CONTRACT_SIGNED: ["PAYMENT_PROCESSING", "LOST"],
  PAYMENT_PROCESSING: ["TX_COMPLETED", "LOST"],
  TX_COMPLETED: [], // Terminal state
  LOST: ["INQUIRY"], // Can restart from LOST
};

/**
 * GET /api/real-estate/transactions/[id]
 * Transaction detail with property and full history.
 */
export const GET = withRateLimit(
  async (
    request: NextRequest,
    { params }: { params: Promise<{ id: string }> },
  ) => {
    try {
      const { id } = await params;

      const userEmail = await getAuthenticatedEmail(request, auth);
      if (!userEmail) {
        return ApiResponses.unauthorized();
      }

      const user = await prisma.users.findUnique({
        where: { email: userEmail },
        select: { id: true },
      });
      if (!user) {
        return ApiResponses.notFound("User not found");
      }

      const effectiveUserId = await getEffectiveOwnerId(user.id);

      // Convex branch
      if (getDataSource("real_estate") === "convex") {
        try {
          const { convexQuery } = await import("@/lib/convex-client");
          const result = await convexQuery(
            "real_estate/queries:getTransactionById",
            { id, userId: effectiveUserId },
          );
          if (result) {
            return ApiResponses.success({
              transaction: result,
              relatedViewings: [],
              timeline: [],
              allowedTransitions: [],
            });
          }
          return ApiResponses.notFound("Transaction not found");
        } catch (error) {
          console.error(
            "[Convex fallback] real_estate transaction GET:",
            error,
          );
        }
      }

      const transaction = await prisma.realEstateTransaction.findFirst({
        where: { id, userId: effectiveUserId },
        include: {
          property: {
            include: {
              images: {
                orderBy: { sortOrder: "asc" },
                take: 5,
              },
              listingBroker: {
                select: { id: true, nameEn: true, nameAr: true, phone: true },
              },
            },
          },
        },
      });

      if (!transaction) {
        return ApiResponses.notFound("Transaction not found");
      }

      // Get related viewings for this property+client combination
      const relatedViewings = await prisma.propertyViewing.findMany({
        where: {
          propertyId: transaction.propertyId,
          clientPhone: transaction.clientPhone,
          userId: effectiveUserId,
        },
        orderBy: { viewingDate: "desc" },
        select: {
          id: true,
          viewingDate: true,
          viewingTime: true,
          status: true,
          interestLevel: true,
          clientNotes: true,
        },
      });

      // Build timeline from transaction timestamps
      const timeline: Array<{ stage: string; date: string | null }> = [];
      timeline.push({
        stage: "Created",
        date: transaction.createdAt.toISOString(),
      });
      if (transaction.offerDate) {
        timeline.push({
          stage: "Offer Made",
          date: transaction.offerDate.toISOString(),
        });
      }
      if (transaction.contractDate) {
        timeline.push({
          stage: "Contract Signed",
          date: transaction.contractDate.toISOString(),
        });
      }
      if (transaction.depositPaidAt) {
        timeline.push({
          stage: "Deposit Paid",
          date: transaction.depositPaidAt.toISOString(),
        });
      }
      if (transaction.completionDate) {
        timeline.push({
          stage: "Completed",
          date: transaction.completionDate.toISOString(),
        });
      }
      if (transaction.handoverDate) {
        timeline.push({
          stage: "Handover",
          date: transaction.handoverDate.toISOString(),
        });
      }

      // Get allowed next transitions
      const allowedTransitions = VALID_TRANSITIONS[transaction.stage] || [];

      return ApiResponses.success({
        transaction,
        relatedViewings,
        timeline,
        allowedTransitions,
      });
    } catch (error) {
      logger.error("[Transaction Detail API] GET error", {
        error: getErrorMessage(error),
      });
      return ApiResponses.serverError("Failed to fetch transaction details");
    }
  },
  rateLimiters.authGeneral,
);

/**
 * PUT /api/real-estate/transactions/[id]
 * Update stage/details. Validate stage transitions.
 * When TX_COMPLETED: update property status to SOLD/RENTED.
 * When LOST: optionally return property to AVAILABLE.
 */
export const PUT = withRateLimit(
  withCSRF(
    async (
      request: NextRequest,
      { params }: { params: Promise<{ id: string }> },
    ) => {
      try {
        const { id } = await params;

        const userEmail = await getAuthenticatedEmail(request, auth);
        if (!userEmail) {
          return ApiResponses.unauthorized();
        }

        const user = await prisma.users.findUnique({
          where: { email: userEmail },
          select: { id: true },
        });
        if (!user) {
          return ApiResponses.notFound("User not found");
        }

        const effectiveUserId = await getEffectiveOwnerId(user.id);

        // Convex branch
        if (getDataSource("real_estate") === "convex") {
          try {
            const body = await request.json();
            const { convexMutation } = await import("@/lib/convex-client");
            const result = await convexMutation(
              "real_estate/mutations:updateTransaction",
              { id, userId: effectiveUserId, ...body },
            );
            return ApiResponses.success({
              transaction: result,
              sideEffects: [],
              allowedTransitions: [],
            });
          } catch (error) {
            console.error(
              "[Convex fallback] real_estate transaction PUT:",
              error,
            );
          }
        }

        const existing = await prisma.realEstateTransaction.findFirst({
          where: { id, userId: effectiveUserId },
          include: {
            property: {
              select: { id: true, listingType: true, status: true },
            },
          },
        });
        if (!existing) {
          return ApiResponses.notFound("Transaction not found");
        }

        const body = await request.json();

        // Validate stage transition if stage change requested
        if (body.stage && body.stage !== existing.stage) {
          const allowed = VALID_TRANSITIONS[existing.stage] || [];
          if (!allowed.includes(body.stage)) {
            return ApiResponses.badRequest(
              `Invalid stage transition from ${existing.stage} to ${body.stage}. Allowed: ${allowed.join(", ") || "none (terminal state)"}`,
            );
          }
        }

        // Build update data
        const updateData: Record<string, unknown> = {};
        const allowedFields = [
          "stage",
          "offerAmount",
          "counterAmount",
          "agreedAmount",
          "currency",
          "depositAmount",
          "depositPaid",
          "depositPaymentId",
          "offerDate",
          "contractDate",
          "completionDate",
          "handoverDate",
          "notes",
          "lostReason",
          "clientName",
          "clientPhone",
          "clientEmail",
          "brokerId",
        ];

        for (const field of allowedFields) {
          if (body[field] !== undefined) {
            // Handle date fields
            if (
              [
                "offerDate",
                "contractDate",
                "completionDate",
                "handoverDate",
              ].includes(field)
            ) {
              updateData[field] = body[field] ? new Date(body[field]) : null;
            } else if (typeof body[field] === "string") {
              updateData[field] = body[field].trim();
            } else {
              updateData[field] = body[field];
            }
          }
        }

        // Auto-set timestamps based on stage changes
        if (body.stage === "OFFER_MADE" && !body.offerDate) {
          updateData.offerDate = new Date();
        }
        if (body.stage === "CONTRACT_SIGNED" && !body.contractDate) {
          updateData.contractDate = new Date();
        }
        if (body.stage === "DEPOSIT_PAID") {
          updateData.depositPaid = true;
          if (!body.depositPaidAt) {
            updateData.depositPaidAt = new Date();
          }
        }
        if (body.stage === "TX_COMPLETED" && !body.completionDate) {
          updateData.completionDate = new Date();
        }

        const transaction = await prisma.realEstateTransaction.update({
          where: { id },
          data: updateData,
          include: {
            property: {
              select: {
                id: true,
                titleEn: true,
                price: true,
                currency: true,
                listingType: true,
              },
            },
          },
        });

        // Side effects on stage transitions
        const sideEffects: string[] = [];

        // TX_COMPLETED: Update property status to SOLD or RENTED
        if (body.stage === "TX_COMPLETED") {
          const newStatus =
            existing.property.listingType === "SALE" ? "SOLD" : "RENTED";
          await prisma.property.update({
            where: { id: existing.propertyId },
            data: {
              status: newStatus,
              soldRentedAt: new Date(),
            },
          });
          sideEffects.push(`Property status updated to ${newStatus}`);

          // Update broker stats if applicable
          if (existing.brokerId) {
            await prisma.broker.update({
              where: { id: existing.brokerId },
              data: { totalClosings: { increment: 1 } },
            });
            sideEffects.push("Broker closing count incremented");
          }
        }

        // LOST: Optionally return property to AVAILABLE
        if (body.stage === "LOST" && body.returnPropertyToAvailable === true) {
          if (existing.property.status === "UNDER_OFFER") {
            await prisma.property.update({
              where: { id: existing.propertyId },
              data: { status: "AVAILABLE" },
            });
            sideEffects.push("Property returned to AVAILABLE");
          }
        }

        logger.info("[Transaction Detail API] Transaction updated", {
          txId: id,
          fromStage: existing.stage,
          toStage: body.stage || existing.stage,
          sideEffects,
        });

        return ApiResponses.success({
          transaction,
          sideEffects,
          allowedTransitions: VALID_TRANSITIONS[transaction.stage] || [],
        });
      } catch (error) {
        logger.error("[Transaction Detail API] PUT error", {
          error: getErrorMessage(error),
        });
        return ApiResponses.serverError("Failed to update transaction");
      }
    },
  ),
  rateLimiters.authGeneral,
);
