import { Request, Response } from "express";
import {
  getAllPuzzles,
  startAttempt,
  updateAttemptProgress,
  submitAttempt,
  getUserAttempts,
  addPuzzle,
  getRandomPuzzle,
  updatePuzzle,
  deletePuzzle,
} from "../services/ziplineService";
import { Types } from "mongoose";
import { sendResponse, handleError } from '../utils/apiResponse';
import ZiplinePuzzle from '../models/ziplinePuzzle';

// GET /api/games/zipline
export const getZiplineLevels = async (req: Request, res: Response) => {
  try {
    const puzzles = await getAllPuzzles();
    sendResponse(res, 200, 'Zipline puzzles fetched', { puzzles });
  } catch (error) {
    handleError(res, error);
  }
};

// POST /api/games/zipline/start
export const startZiplineAttempt = async (req: Request, res: Response) => {
  try {
    if (!req.user || !req.user._id) {
      return sendResponse(res, 401, 'Unauthorized: user not found');
    }
    const body = req.body || {};
    let { puzzleId, difficulty } = body;
    const userId = req.user._id;
    let puzzle;
    // If no puzzleId is provided, pick a random available puzzle (optionally by difficulty)
    if (!puzzleId) {
      puzzle = await getRandomPuzzle(difficulty);
      if (!puzzle) {
        return sendResponse(res, 404, 'No available puzzles found');
      }
      puzzleId = puzzle._id;
    } else {
      // Fetch the puzzle details (excluding solution)
      puzzle = await ZiplinePuzzle.findById(puzzleId).select(
        '_id title description difficulty grid numbers blocks',
      );
      if (!puzzle) {
        return sendResponse(res, 404, 'Puzzle not found');
      }
    }
    const attempt = await startAttempt({ userId, puzzleId });
    sendResponse(res, 200, 'Zipline attempt started', {
      attemptId: attempt._id,
      puzzle,
    });
  } catch (error) {
    handleError(res, error);
  }
};

// PATCH /api/games/zipline/attempt/:attemptId
export const updateZiplineAttempt = async (req: Request, res: Response) => {
  try {
    let { attemptId } = req.params;
    const { progress } = req.body;
    if (Array.isArray(attemptId)) attemptId = attemptId[0];
    const attempt = await updateAttemptProgress({
      attemptId: new Types.ObjectId(attemptId),
      progress,
    });
    sendResponse(res, 200, 'Zipline attempt updated', { attempt });
  } catch (error) {
    handleError(res, error);
  }
};

// POST /api/games/zipline/attempt/:attemptId/submit
export const submitZiplineAttempt = async (req: Request, res: Response) => {
  try {
    let { attemptId } = req.params;
    const { submittedSolution } = req.body;
    if (Array.isArray(attemptId)) attemptId = attemptId[0];
    const result = await submitAttempt({
      attemptId: new Types.ObjectId(attemptId),
      submittedSolution: req.body,
    });
    sendResponse(res, 200, 'Zipline attempt submitted', result);
  } catch (error) {
    handleError(res, error);
  }
};

// GET /api/games/zipline/my-attempts
export const getMyZiplineAttempts = async (req: Request, res: Response) => {
  try {
    if (!req.user || !req.user._id) {
      return sendResponse(res, 401, 'Unauthorized: user not found');
    }
    const userId = req.user._id;
    const attempts = await getUserAttempts(userId);
    sendResponse(res, 200, 'Zipline attempts fetched', { attempts });
  } catch (error) {
    handleError(res, error);
  }
};

// ADMIN: POST /api/games/zipline (add a new puzzle)
export const addZiplinePuzzle = async (req: Request, res: Response) => {
  try {
    const { grid, numbers, blocks, solution, difficulty, title, description } = req.body;
    const puzzle = await addPuzzle({
      grid,
      numbers,
      blocks,
      solution,
      difficulty,
      title,
      description,
    });
    sendResponse(res, 201, 'Zipline puzzle added', { puzzle });
  } catch (error) {
    handleError(res, error);
  }
};

// ADMIN: PUT /api/games/zipline/:puzzleId (update puzzle)
export const updateZiplinePuzzle = async (req: Request, res: Response) => {
  try {
    let { puzzleId } = req.params;
    if (Array.isArray(puzzleId)) puzzleId = puzzleId[0];

    const puzzle = await updatePuzzle(puzzleId, req.body);
    sendResponse(res, 200, 'Zipline puzzle updated', { puzzle });
  } catch (error) {
    handleError(res, error);
  }
};

// ADMIN: DELETE /api/games/zipline/:puzzleId (delete puzzle)
export const deleteZiplinePuzzle = async (req: Request, res: Response) => {
  try {
    let { puzzleId } = req.params;
    if (Array.isArray(puzzleId)) puzzleId = puzzleId[0];

    const result = await deletePuzzle(puzzleId);
    sendResponse(res, 200, 'Zipline puzzle deleted', result);
  } catch (error) {
    handleError(res, error);
  }
};