/**
 * @ai-summary HTTP request handlers for community stations API
 * @ai-context Handles user submissions and admin review operations
 */

import { FastifyRequest, FastifyReply } from 'fastify';
import { CommunityStationsService } from '../domain/community-stations.service';
import { CommunityStationsRepository } from '../data/community-stations.repository';
import { pool } from '../../../core/config/database';
import { AdminRepository } from '../../admin/data/admin.repository';
import { logger } from '../../../core/logging/logger';
import {
  SubmitCommunityStationInput,
  ReviewStationInput,
  CommunityStationFiltersInput,
  NearbyStationsInput,
  StationIdInput,
  PaginationInput,
  BoundsStationsInput,
  RemovalReportInput,
  submitCommunityStationSchema,
  reviewStationSchema,
  communityStationFiltersSchema,
  nearbyStationsSchema,
  stationIdSchema,
  paginationSchema,
  boundsStationsSchema,
  removalReportSchema
} from './community-stations.validation';

export class CommunityStationsController {
  private service: CommunityStationsService;
  private adminRepository: AdminRepository;

  constructor() {
    const repository = new CommunityStationsRepository(pool);
    this.service = new CommunityStationsService(repository);
    this.adminRepository = new AdminRepository(pool);
  }

  /**
   * POST /api/stations/community
   * Submit a new community gas station
   */
  async submitStation(
    request: FastifyRequest<{ Body: SubmitCommunityStationInput }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      const userId = (request as any).user.sub;

      // Validate request body
      const validation = submitCommunityStationSchema.safeParse(request.body);
      if (!validation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: validation.error.errors
        });
      }

      const station = await this.service.submitStation(userId, validation.data);

      return reply.code(201).send(station);
    } catch (error: any) {
      logger.error('Error submitting station', { error, userId: (request as any).user?.sub });
      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to submit station'
      });
    }
  }

  /**
   * GET /api/stations/community/mine
   * Get user's own station submissions
   */
  async getMySubmissions(
    request: FastifyRequest<{ Querystring: PaginationInput }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      const userId = (request as any).user.sub;

      // Validate query params
      const validation = paginationSchema.safeParse(request.query);
      if (!validation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: validation.error.errors
        });
      }

      const result = await this.service.getMySubmissions(userId, validation.data.limit, validation.data.offset);

      return reply.code(200).send(result);
    } catch (error: any) {
      logger.error('Error getting user submissions', { error, userId: (request as any).user?.sub });
      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to retrieve submissions'
      });
    }
  }

  /**
   * DELETE /api/stations/community/:id
   * Withdraw a pending submission
   */
  async withdrawSubmission(
    request: FastifyRequest<{ Params: StationIdInput }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      const userId = (request as any).user.sub;

      // Validate params
      const validation = stationIdSchema.safeParse(request.params);
      if (!validation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: validation.error.errors
        });
      }

      await this.service.withdrawSubmission(userId, validation.data.id);

      return reply.code(204).send();
    } catch (error: any) {
      logger.error('Error withdrawing submission', {
        error,
        userId: (request as any).user?.sub,
        stationId: request.params.id
      });

      if (error.message.includes('not found')) {
        return reply.code(404).send({
          error: 'Not found',
          message: 'Station not found'
        });
      }

      if (error.message.includes('Unauthorized') || error.message.includes('pending')) {
        return reply.code(400).send({
          error: 'Bad request',
          message: error.message
        });
      }

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to withdraw submission'
      });
    }
  }

  /**
   * GET /api/stations/community/approved
   * Get list of approved community stations (public)
   */
  async getApprovedStations(
    request: FastifyRequest<{ Querystring: PaginationInput }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      // Validate query params
      const validation = paginationSchema.safeParse(request.query);
      if (!validation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: validation.error.errors
        });
      }

      const result = await this.service.getApprovedStations(validation.data.limit, validation.data.offset);

      return reply.code(200).send(result);
    } catch (error: any) {
      logger.error('Error getting approved stations', { error });
      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to retrieve stations'
      });
    }
  }

  /**
   * POST /api/stations/community/nearby
   * Find approved stations near a location
   */
  async getNearbyStations(
    request: FastifyRequest<{ Body: NearbyStationsInput }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      // Validate request body
      const validation = nearbyStationsSchema.safeParse(request.body);
      if (!validation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: validation.error.errors
        });
      }

      const stations = await this.service.getApprovedNearby(validation.data);

      return reply.code(200).send({ stations });
    } catch (error: any) {
      logger.error('Error getting nearby stations', { error });
      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to retrieve nearby stations'
      });
    }
  }

  /**
   * POST /api/stations/community/bounds
   * Find approved stations within map bounds
   */
  async getStationsInBounds(
    request: FastifyRequest<{ Body: BoundsStationsInput }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      // Validate request body
      const validation = boundsStationsSchema.safeParse(request.body);
      if (!validation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: validation.error.errors
        });
      }

      const stations = await this.service.getApprovedInBounds(validation.data);

      return reply.code(200).send({ stations });
    } catch (error: any) {
      logger.error('Error getting stations in bounds', { error });
      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to retrieve stations'
      });
    }
  }

  /**
   * POST /api/stations/community/:id/report-removal
   * Report that a station no longer has Premium 93
   */
  async reportRemoval(
    request: FastifyRequest<{ Params: StationIdInput; Body: RemovalReportInput }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      const userId = (request as any).user.sub;

      // Validate params
      const paramsValidation = stationIdSchema.safeParse(request.params);
      if (!paramsValidation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: paramsValidation.error.errors
        });
      }

      // Validate body
      const bodyValidation = removalReportSchema.safeParse(request.body);
      if (!bodyValidation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: bodyValidation.error.errors
        });
      }

      const result = await this.service.submitRemovalReport(
        userId,
        paramsValidation.data.id,
        bodyValidation.data.reason
      );

      return reply.code(200).send(result);
    } catch (error: any) {
      logger.error('Error reporting removal', { error, userId: (request as any).user?.sub });

      if (error.message.includes('not found')) {
        return reply.code(404).send({
          error: 'Not found',
          message: 'Station not found'
        });
      }

      if (error.message.includes('already reported')) {
        return reply.code(409).send({
          error: 'Conflict',
          message: 'You have already reported this station'
        });
      }

      if (error.message.includes('already been removed')) {
        return reply.code(400).send({
          error: 'Bad request',
          message: 'Station has already been removed'
        });
      }

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to submit removal report'
      });
    }
  }

  /**
   * GET /api/admin/community-stations
   * List all submissions with filters (admin only)
   */
  async listAllSubmissions(
    request: FastifyRequest<{ Querystring: CommunityStationFiltersInput }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      // Validate query params
      const validation = communityStationFiltersSchema.safeParse(request.query);
      if (!validation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: validation.error.errors
        });
      }

      const result = await this.service.getStationsForAdmin(validation.data);

      return reply.code(200).send(result);
    } catch (error: any) {
      logger.error('Error listing submissions', { error });
      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to list submissions'
      });
    }
  }

  /**
   * GET /api/admin/community-stations/pending
   * Get pending submissions queue (admin only)
   */
  async getPendingQueue(
    request: FastifyRequest<{ Querystring: PaginationInput }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      // Validate query params
      const validation = paginationSchema.safeParse(request.query);
      if (!validation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: validation.error.errors
        });
      }

      const result = await this.service.getPendingReview(validation.data.limit, validation.data.offset);

      return reply.code(200).send(result);
    } catch (error: any) {
      logger.error('Error getting pending queue', { error });
      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to retrieve pending submissions'
      });
    }
  }

  /**
   * PATCH /api/admin/community-stations/:id/review
   * Approve or reject a submission (admin only)
   */
  async reviewStation(
    request: FastifyRequest<{ Params: StationIdInput; Body: ReviewStationInput }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      const adminId = (request as any).user.sub;

      // Validate params
      const paramsValidation = stationIdSchema.safeParse(request.params);
      if (!paramsValidation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: paramsValidation.error.errors
        });
      }

      // Validate body
      const bodyValidation = reviewStationSchema.safeParse(request.body);
      if (!bodyValidation.success) {
        return reply.code(400).send({
          error: 'Validation error',
          details: bodyValidation.error.errors
        });
      }

      const station = await this.service.reviewStation(
        adminId,
        paramsValidation.data.id,
        bodyValidation.data.status,
        bodyValidation.data.rejectionReason
      );

      // Log audit action
      await this.adminRepository.logAuditAction(
        adminId,
        'REVIEW',
        undefined,
        'community_station',
        paramsValidation.data.id,
        {
          status: bodyValidation.data.status,
          submittedBy: station.submittedBy,
          name: station.name
        }
      );

      return reply.code(200).send(station);
    } catch (error: any) {
      logger.error('Error reviewing station', { error, adminId: (request as any).user?.sub });

      if (error.message.includes('not found')) {
        return reply.code(404).send({
          error: 'Not found',
          message: 'Station not found'
        });
      }

      if (error.message.includes('Rejection reason')) {
        return reply.code(400).send({
          error: 'Bad request',
          message: error.message
        });
      }

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to review station'
      });
    }
  }
}
