/**
 * Real Estate Transactions API
 * GET  - List transactions with kanban view support
 * POST - Create a new transaction
 */

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 { createId } from "@paralleldrive/cuid2";
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 stages in pipeline order
const STAGE_ORDER: TransactionStage[] = [
  "INQUIRY",
  "QUALIFIED",
  "VIEWING_SCHEDULED",
  "VIEWING_COMPLETED",
  "INTERESTED",
  "OFFER_MADE",
  "NEGOTIATION",
  "OFFER_ACCEPTED",
  "DEPOSIT_PAID",
  "CONTRACT_SIGNED",
  "PAYMENT_PROCESSING",
  "TX_COMPLETED",
  "LOST",
];

/**
 * GET /api/real-estate/transactions
 * List transactions. Filter by stage.
 * Support kanban view (group by stage with counts and pipeline value).
 */
export const GET = withRateLimit(async (request: NextRequest) => {
  try {
    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 stageParam = request.nextUrl.searchParams.get("stage");
        const convexTxns = await convexQuery(
          "real_estate/queries:getTransactions",
          {
            userId: effectiveUserId,
            ...(stageParam ? { stage: stageParam } : {}),
          },
        );
        if (convexTxns !== null) {
          return ApiResponses.success({
            transactions: convexTxns,
            count: (convexTxns as unknown[]).length,
          });
        }
      } catch (convexErr) {
        console.error(
          "[Convex fallback] real_estate transactions GET:",
          convexErr,
        );
      }
    }

    const stageFilter = request.nextUrl.searchParams.get(
      "stage",
    ) as TransactionStage | null;
    const view = request.nextUrl.searchParams.get("view"); // 'kanban' for grouped view

    const where = {
      userId: effectiveUserId,
      ...(stageFilter ? { stage: stageFilter } : {}),
    };

    const transactions = await prisma.realEstateTransaction.findMany({
      where,
      include: {
        property: {
          select: {
            id: true,
            titleEn: true,
            titleAr: true,
            price: true,
            currency: true,
            propertyType: true,
            city: true,
            district: true,
          },
        },
      },
      orderBy: { updatedAt: "desc" },
    });

    // If kanban view requested, group by stage
    if (view === "kanban") {
      const kanban: Record<
        string,
        {
          stage: string;
          count: number;
          totalValue: number;
          transactions: typeof transactions;
        }
      > = {};

      // Initialize all stages
      for (const stage of STAGE_ORDER) {
        kanban[stage] = { stage, count: 0, totalValue: 0, transactions: [] };
      }

      for (const tx of transactions) {
        const stage = tx.stage;
        if (!kanban[stage]) {
          kanban[stage] = { stage, count: 0, totalValue: 0, transactions: [] };
        }
        kanban[stage].count++;
        kanban[stage].totalValue += tx.agreedAmount || tx.offerAmount || 0;
        kanban[stage].transactions.push(tx);
      }

      const totalPipelineValue = transactions.reduce(
        (sum, tx) => sum + (tx.agreedAmount || tx.offerAmount || 0),
        0,
      );

      return ApiResponses.success({
        view: "kanban",
        totalTransactions: transactions.length,
        totalPipelineValue,
        stages: STAGE_ORDER.map((stage) => kanban[stage]),
      });
    }

    // Default list view
    return ApiResponses.success({
      transactions,
      count: transactions.length,
    });
  } catch (error) {
    logger.error("[Transactions API] GET error", {
      error: getErrorMessage(error),
    });
    return ApiResponses.serverError("Failed to fetch transactions");
  }
}, rateLimiters.authGeneral);

/**
 * POST /api/real-estate/transactions
 * Create a new transaction.
 */
export const POST = withRateLimit(
  withCSRF(async (request: NextRequest) => {
    try {
      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 convexBody = await request.json();
          if (!convexBody.propertyId) {
            return ApiResponses.badRequest("propertyId is required");
          }
          if (!convexBody.clientName?.trim()) {
            return ApiResponses.badRequest("clientName is required");
          }
          if (!convexBody.clientPhone?.trim()) {
            return ApiResponses.badRequest("clientPhone is required");
          }
          const { convexMutation } = await import("@/lib/convex-client");
          const convexResult = await convexMutation(
            "real_estate/mutations:createTransaction",
            {
              userId: effectiveUserId,
              propertyId: convexBody.propertyId,
              clientName: convexBody.clientName.trim(),
              clientPhone: convexBody.clientPhone.trim(),
              clientEmail: convexBody.clientEmail?.trim(),
              brokerId: convexBody.brokerId,
              stage: convexBody.stage,
              offerAmount: convexBody.offerAmount,
              currency: convexBody.currency,
              notes: convexBody.notes?.trim(),
            },
          );
          return ApiResponses.success({ transaction: convexResult });
        } catch (convexErr) {
          console.error(
            "[Convex fallback] real_estate transactions POST:",
            convexErr,
          );
        }
      }

      const body = await request.json();

      // Validate required fields
      if (!body.propertyId) {
        return ApiResponses.badRequest("propertyId is required");
      }
      if (
        !body.clientName ||
        typeof body.clientName !== "string" ||
        body.clientName.trim().length === 0
      ) {
        return ApiResponses.badRequest("clientName is required");
      }
      if (
        !body.clientPhone ||
        typeof body.clientPhone !== "string" ||
        body.clientPhone.trim().length === 0
      ) {
        return ApiResponses.badRequest("clientPhone is required");
      }

      // Verify property exists and belongs to org
      const property = await prisma.property.findFirst({
        where: { id: body.propertyId, userId: effectiveUserId },
        select: { id: true, titleEn: true, price: true, currency: true },
      });
      if (!property) {
        return ApiResponses.notFound("Property not found");
      }

      // Validate stage if provided
      if (body.stage && !STAGE_ORDER.includes(body.stage)) {
        return ApiResponses.badRequest(
          `Invalid stage. Must be one of: ${STAGE_ORDER.join(", ")}`,
        );
      }

      // Validate broker if provided
      if (body.brokerId) {
        const broker = await prisma.broker.findFirst({
          where: { id: body.brokerId, userId: effectiveUserId, isActive: true },
        });
        if (!broker) {
          return ApiResponses.notFound("Broker not found or inactive");
        }
      }

      // Look up organizationId
      const membership = await prisma.organization_members.findFirst({
        where: { userId: user.id },
        select: { organizationId: true },
      });

      const transaction = await prisma.realEstateTransaction.create({
        data: {
          id: createId(),
          userId: effectiveUserId,
          organizationId: membership?.organizationId || null,
          propertyId: body.propertyId,
          clientName: body.clientName.trim(),
          clientPhone: body.clientPhone.trim(),
          clientEmail: body.clientEmail?.trim() || null,
          brokerId: body.brokerId || null,
          stage: body.stage || "INQUIRY",
          offerAmount: body.offerAmount ?? null,
          currency: property.currency || "QAR",
          notes: body.notes?.trim() || null,
        },
        include: {
          property: {
            select: {
              id: true,
              titleEn: true,
              titleAr: true,
              price: true,
              currency: true,
            },
          },
        },
      });

      logger.info("[Transactions API] Transaction created", {
        txId: transaction.id,
        propertyId: body.propertyId,
        stage: transaction.stage,
      });

      return ApiResponses.success({ transaction });
    } catch (error) {
      logger.error("[Transactions API] POST error", {
        error: getErrorMessage(error),
      });
      return ApiResponses.serverError("Failed to create transaction");
    }
  }),
  rateLimiters.authGeneral,
);
