/**
 * Viewing Feedback API
 * GET  - Get feedback for a viewing
 * POST - Submit post-viewing feedback (broker observations + client feedback)
 *
 * Supports both NextAuth and OTP (auth_token) authentication
 */

import { NextRequest, NextResponse } 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";
import { sendPostViewingFollowUp } from "@/lib/services/real-estate/notification.service";
import { getDataSource } from "@/lib/data-source";

export const dynamic = "force-dynamic";

// --- Allowed enum values ---
const PRICE_OPINIONS = ["fair", "too_high", "bargain"] as const;
const SIZE_OPINIONS = ["too_small", "just_right", "spacious"] as const;
const LOCATION_OPINIONS = ["convenient", "acceptable", "too_far"] as const;
const INTEREST_LEVELS = ["hot", "warm", "cool", "cold"] as const;
const SUGGESTED_ACTIONS = [
  "make_offer",
  "second_viewing",
  "not_interested",
  "show_similar",
] as const;

/**
 * GET /api/real-estate/viewings/[id]/feedback
 * Returns all feedback records for a given viewing.
 * Verifies the viewing belongs to the authenticated user's organization.
 */
export const GET = withRateLimit(
  async (
    request: NextRequest,
    { params }: { params: Promise<{ id: string }> },
  ) => {
    try {
      const userEmail = await getAuthenticatedEmail(request, auth);

      if (!userEmail) {
        logger.warn("Unauthorized feedback read attempt");
        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);
      const { id: viewingId } = await params;

      if (!viewingId || typeof viewingId !== "string") {
        return ApiResponses.badRequest("Viewing ID is required");
      }

      // Convex branch
      if (getDataSource("real_estate") === "convex") {
        try {
          const { convexQuery } = await import("@/lib/convex-client");
          const result = await convexQuery(
            "real_estate/queries:getViewingById",
            { id: viewingId, userId: effectiveUserId },
          );
          if (result) {
            return NextResponse.json({
              success: true,
              feedback: (result as { feedback: unknown[] }).feedback || [],
            });
          }
          return ApiResponses.notFound("Viewing not found");
        } catch (error) {
          console.error("[Convex fallback] real_estate feedback GET:", error);
        }
      }

      // Verify viewing exists and belongs to user's organization
      const viewing = await prisma.propertyViewing.findFirst({
        where: {
          id: viewingId,
          userId: effectiveUserId,
        },
        select: { id: true },
      });

      if (!viewing) {
        return ApiResponses.notFound("Viewing not found");
      }

      // Fetch all feedback records for this viewing
      const feedback = await prisma.viewingFeedback.findMany({
        where: { viewingId },
        orderBy: { createdAt: "desc" },
      });

      logger.info("Viewing feedback retrieved", {
        viewingId,
        userEmail,
        count: feedback.length,
      });

      return NextResponse.json({
        success: true,
        feedback,
      });
    } catch (error) {
      logger.error("Failed to retrieve viewing feedback", {
        error: getErrorMessage(error),
      });

      return ApiResponses.serverError("Failed to retrieve feedback");
    }
  },
  rateLimiters.authGeneral,
);

/**
 * POST /api/real-estate/viewings/[id]/feedback
 * Submit post-viewing feedback from client or broker.
 *
 * Client fields: overallRating, priceOpinion, sizeOpinion, locationOpinion,
 *                conditionNote, wouldRecommend
 * Broker fields: brokerNotes, interestLevel, suggestedAction
 *
 * Side effects:
 * - Updates viewing.interestLevel if interestLevel is provided
 * - Updates viewing.clientNotes if brokerNotes is provided
 * - Transitions viewing to COMPLETED if interestLevel is 'hot' and status is IN_PROGRESS
 * - Triggers non-blocking post-viewing follow-up notification
 */
export const POST = withRateLimit(
  withCSRF(
    async (
      request: NextRequest,
      { params }: { params: Promise<{ id: string }> },
    ) => {
      try {
        const userEmail = await getAuthenticatedEmail(request, auth);

        if (!userEmail) {
          logger.warn("Unauthorized feedback submission attempt");
          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);
        const { id: viewingId } = await params;

        if (!viewingId || typeof viewingId !== "string") {
          return ApiResponses.badRequest("Viewing ID is required");
        }

        // 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:submitViewingFeedback",
              {
                viewingId,
                overallRating: body.overallRating,
                priceOpinion: body.priceOpinion,
                sizeOpinion: body.sizeOpinion,
                locationOpinion: body.locationOpinion,
                conditionNote: body.conditionNote?.trim(),
                wouldRecommend: body.wouldRecommend,
                brokerNotes: body.brokerNotes?.trim(),
                interestLevel: body.interestLevel,
                suggestedAction: body.suggestedAction,
              },
            );
            // Non-blocking follow-up notification (stays as-is)
            sendPostViewingFollowUp(viewingId).catch((err) => {
              logger.error("Post-viewing follow-up notification failed", {
                viewingId,
                error: getErrorMessage(err),
              });
            });
            return NextResponse.json({ success: true, feedback: result });
          } catch (error) {
            console.error(
              "[Convex fallback] real_estate feedback POST:",
              error,
            );
          }
        }

        // Verify viewing exists and belongs to user's organization
        const viewing = await prisma.propertyViewing.findFirst({
          where: {
            id: viewingId,
            userId: effectiveUserId,
          },
          select: { id: true, status: true },
        });

        if (!viewing) {
          return ApiResponses.notFound("Viewing not found");
        }

        const body = await request.json();
        const {
          overallRating,
          priceOpinion,
          sizeOpinion,
          locationOpinion,
          conditionNote,
          wouldRecommend,
          brokerNotes,
          interestLevel,
          suggestedAction,
        } = body;

        // --- Validation ---
        const errors: string[] = [];

        if (
          overallRating !== undefined &&
          overallRating !== null &&
          (typeof overallRating !== "number" ||
            !Number.isInteger(overallRating) ||
            overallRating < 1 ||
            overallRating > 5)
        ) {
          errors.push("Overall rating must be an integer between 1 and 5");
        }

        if (
          priceOpinion !== undefined &&
          priceOpinion !== null &&
          !PRICE_OPINIONS.includes(priceOpinion)
        ) {
          errors.push(
            `Price opinion must be one of: ${PRICE_OPINIONS.join(", ")}`,
          );
        }

        if (
          sizeOpinion !== undefined &&
          sizeOpinion !== null &&
          !SIZE_OPINIONS.includes(sizeOpinion)
        ) {
          errors.push(
            `Size opinion must be one of: ${SIZE_OPINIONS.join(", ")}`,
          );
        }

        if (
          locationOpinion !== undefined &&
          locationOpinion !== null &&
          !LOCATION_OPINIONS.includes(locationOpinion)
        ) {
          errors.push(
            `Location opinion must be one of: ${LOCATION_OPINIONS.join(", ")}`,
          );
        }

        if (
          interestLevel !== undefined &&
          interestLevel !== null &&
          !INTEREST_LEVELS.includes(interestLevel)
        ) {
          errors.push(
            `Interest level must be one of: ${INTEREST_LEVELS.join(", ")}`,
          );
        }

        if (
          suggestedAction !== undefined &&
          suggestedAction !== null &&
          !SUGGESTED_ACTIONS.includes(suggestedAction)
        ) {
          errors.push(
            `Suggested action must be one of: ${SUGGESTED_ACTIONS.join(", ")}`,
          );
        }

        if (errors.length > 0) {
          return NextResponse.json(
            { success: false, error: errors.join(", "), errors },
            { status: 400 },
          );
        }

        // --- Create feedback record ---
        const feedback = await prisma.viewingFeedback.create({
          data: {
            id: createId(),
            viewingId,
            overallRating: overallRating ?? null,
            priceOpinion: priceOpinion ?? null,
            sizeOpinion: sizeOpinion ?? null,
            locationOpinion: locationOpinion ?? null,
            conditionNote: conditionNote?.trim() || null,
            wouldRecommend:
              wouldRecommend !== undefined ? wouldRecommend : null,
            brokerNotes: brokerNotes?.trim() || null,
            interestLevel: interestLevel ?? null,
            suggestedAction: suggestedAction ?? null,
          },
        });

        logger.info("Viewing feedback created", {
          feedbackId: feedback.id,
          viewingId,
          userEmail,
        });

        // --- Side effects: update the viewing record ---
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const viewingUpdate: any = {};

        if (interestLevel) {
          viewingUpdate.interestLevel = interestLevel;
        }

        if (brokerNotes) {
          viewingUpdate.clientNotes = brokerNotes.trim();
        }

        // Auto-complete viewing when interest is hot and status is still IN_PROGRESS
        if (interestLevel === "hot" && viewing.status === "IN_PROGRESS") {
          viewingUpdate.status = "COMPLETED";
        }

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

          logger.info("Viewing updated from feedback side effects", {
            viewingId,
            updates: Object.keys(viewingUpdate),
          });
        }

        // --- Non-blocking follow-up notification ---
        sendPostViewingFollowUp(viewingId).catch((err) => {
          logger.error("Post-viewing follow-up notification failed", {
            viewingId,
            error: getErrorMessage(err),
          });
        });

        return NextResponse.json({
          success: true,
          feedback,
        });
      } catch (error) {
        logger.error("Failed to submit viewing feedback", {
          error: getErrorMessage(error),
        });

        return ApiResponses.serverError("Failed to submit feedback");
      }
    },
  ),
  rateLimiters.authGeneral,
);
