import { Request, Response, NextFunction, RequestHandler } from "express";
import { PricingPlan } from "../models/PricingPlan";
import { Query } from "../models/Queries";
import { QueryBuilder } from "objection";

interface PricingPlanRequestBody {
  plan_name: string;
  price: string;
  discount: string;
  duration: "weekly" | "monthly" | "quarterly" | "yearly";
  is_popular: boolean;
  is_trial: boolean;
  queries_id: number;
  custom_fields?: { key: string; type: string; value: string }[];
}

function formatMySQLDate(date: Date) {
  return date.toISOString().slice(0, 19).replace("T", " ");
}

export class PricingPlansController {
  private sendError(res: Response, status: number, message: string): void {
    res.status(status).json({ message });
  }

  private sendSuccess(res: Response, message: string, data?: any): void {
    res.status(200).json({ success: true, message, data });
  }
  show: RequestHandler = async (req, res, next): Promise<void> => {
    try {
      const pricingplans = await PricingPlan.query()
        .select(
          "id",
          "plan_name",
          "price",
          "discount",
          "duration",
          "is_popular",
          "is_trial",
          "queries_id",
          "benefits"
        )
        .withGraphFetched("query") // eager load query relation
        .modifyGraph(
          "query",
          (builder: any) =>
            builder.select(
              "id",
              "query_name",
              "total_token",
              "total_characters"
            ) // only get needed fields
        );

      this.sendSuccess(res, "Pricing Plans fetched successfully", pricingplans);
    } catch (err) {
      console.error("Error fetching Pricing Plans:", err);
      next(err);
    }
  };

  add: RequestHandler = async (
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    const now = formatMySQLDate(new Date());

    try {
      const request = req.body as PricingPlanRequestBody;

      // Define required fields
      const requiredFields = [
        "plan_name",
        "price",
        "discount",
        "duration",
        "is_popular",
        "is_trial",
        "queries_id",
      ];

      // Check for missing fields
      const missingFields = requiredFields.filter(
        (field) => !(field in request)
      );
      if (missingFields.length) {
        res.status(400).json({
          message: `Missing required fields: ${missingFields.join(", ")}`,
        });
        return;
      }

      // Validate custom_fields format
      let benefits: { key: string; type: string; value: string }[] = [];
      if (Array.isArray(request.custom_fields)) {
        const isValid = request.custom_fields.every(
          (field) =>
            typeof field === "object" &&
            typeof field.key === "string" &&
            typeof field.type === "string" &&
            typeof field.value === "string"
        );
        if (!isValid) {
          res.status(400).json({ message: "Invalid custom_fields format" });
          return;
        }
        benefits = request.custom_fields;
      }

      // Check for existing plan name
      const existingPlanName = await PricingPlan.query().findOne({
        plan_name: request.plan_name,
      });

      if (existingPlanName) {
        res.status(409).json({
          message: `Plan name "${request.plan_name}" already exists`,
        });
        return;
      }

      // Insert into database
      const pricingPlan = await PricingPlan.query().insert({
        discount: request.discount,
        duration: request.duration,
        is_popular: request.is_popular,
        is_trial: request.is_trial,
        plan_name: request.plan_name.trim(), // Trim whitespace
        price: request.price,
        queries_id: request.queries_id,
        benefits: benefits, // Handle empty array
        // created_at: now,
        // updated_at: now,
      });

      res.status(201).json({
        message: "Pricing Plan created successfully",
        data: pricingPlan,
      });
    } catch (error: any) {
      console.error("Error creating Pricing Plan:", error.message, error);
      res.status(500).json({
        message: `Failed to create Pricing Plan: ${
          error.message || "Unknown error"
        }`,
      });
    }
  };

  get: RequestHandler = async (
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    try {
      const { id } = req.params;

      if (!id) {
        this.sendError(res, 400, "Missing tool page ID");
        return;
      }

      const pricingPlan = await PricingPlan.query()
        .findById(id)
        .withGraphFetched("query")
        .modifyGraph("query", (builder: QueryBuilder<Query>) => {
          builder.select("id", "query_name");
        });

      if (!pricingPlan) {
        this.sendError(res, 404, "Tool page not found");
        return;
      }

      this.sendSuccess(res, "Tool page fetched successfully", pricingPlan);
    } catch (error) {
      console.error("Error fetching tool page:", error);
      this.sendError(res, 500, "Internal server error");
    }
  };

  edit: RequestHandler = async (
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    const now = formatMySQLDate(new Date());

    try {
      const { id } = req.params; // plan id from route param
      const request = req.body as PricingPlanRequestBody;

      if (!id) {
        res.status(400).json({ message: "Missing required parameter: id" });
        return;
      }

      // Find existing plan
      const existingPlan = await PricingPlan.query().findById(id);
      if (!existingPlan) {
        res
          .status(404)
          .json({ message: `Pricing Plan with id ${id} not found` });
        return;
      }

      // Define required fields
      const requiredFields = [
        "plan_name",
        "price",
        "discount",
        "duration",
        "is_popular",
        "is_trial",
        "queries_id",
      ];

      // Check for missing fields
      const missingFields = requiredFields.filter(
        (field) => !(field in request)
      );
      if (missingFields.length) {
        res.status(400).json({
          message: `Missing required fields: ${missingFields.join(", ")}`,
        });
        return;
      }

      // Validate custom_fields format
      let benefits: { key: string; type: string; value: string }[] = [];
      if (Array.isArray(request.custom_fields)) {
        const isValid = request.custom_fields.every(
          (field) =>
            typeof field === "object" &&
            typeof field.key === "string" &&
            typeof field.type === "string" &&
            typeof field.value === "string"
        );
        if (!isValid) {
          res.status(400).json({ message: "Invalid custom_fields format" });
          return;
        }
        benefits = request.custom_fields;
      }

      // Check for duplicate plan_name (ignore current plan)
      const duplicatePlan = await PricingPlan.query()
        .findOne({ plan_name: request.plan_name })
        .whereNot("id", id);

      if (duplicatePlan) {
        res.status(409).json({
          message: `Plan name "${request.plan_name}" already exists`,
        });
        return;
      }

      // Update record
      const updatedPlan = await PricingPlan.query().patchAndFetchById(id, {
        discount: request.discount,
        duration: request.duration,
        is_popular: request.is_popular,
        is_trial: request.is_trial,
        plan_name: request.plan_name.trim(),
        price: request.price,
        queries_id: request.queries_id,
        benefits: benefits,
        // updated_at: now,
      });

      res.status(200).json({
        message: "Pricing Plan updated successfully",
        data: updatedPlan,
      });
    } catch (error: any) {
      console.error("Error updating Pricing Plan:", error.message, error);
      res.status(500).json({
        message: `Failed to update Pricing Plan: ${
          error.message || "Unknown error"
        }`,
      });
    }
  };

  delete: RequestHandler = async (
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    try {
      const { id } = req.params;

      if (!id) {
        this.sendError(res, 400, "Missing tool page ID");
        return;
      }

      const toolPage = await PricingPlan.query().findById(id);
      if (!toolPage) {
        this.sendError(res, 404, "Tool page not found");
        return;
      }

      await PricingPlan.query().deleteById(id);

      this.sendSuccess(res, "Tool page deleted successfully");
    } catch (error) {
      console.error("Error deleting tool page:", error);
      this.sendError(res, 500, "Failed to delete tool page");
    }
  };

}
