import {
  Body,
  Controller,
  Delete,
  Get,
  InternalServerErrorException,
  Logger,
  Post,
  Query,
  Param,
  Put,
} from '@nestjs/common';
import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
import { Public } from '../../../modules/auth/public.decorator';
import { DashboardService } from '../../../modules/dashboard/dashboard.service';
import { DataSource } from 'typeorm';

@ApiTags('mobile_saved_jobs')
@Controller('mobile/seeker')
export class MobileSavedJobsController {
  private readonly logger = new Logger(MobileSavedJobsController.name);

  constructor(
    private readonly dashboardService: DashboardService,
    private readonly dataSource: DataSource,
  ) {}

  private getTimeAgoString(createdAt: any): string {
    const createdDate = createdAt ? new Date(createdAt) : null;
    const now = new Date();

    if (!createdDate || Number.isNaN(createdDate.getTime())) {
      return '';
    }

    const diffMs = now.getTime() - createdDate.getTime();
    if (diffMs < 0) return 'just now';

    const minutes = Math.floor(diffMs / (60 * 1000));
    if (minutes < 1) return 'just now';
    if (minutes < 60) return `${minutes} minutes ago`;

    const hours = Math.floor(minutes / 60);
    if (hours < 24) return `${hours} hours ago`;

    const days = Math.floor(hours / 24);
    if (days < 30) return `${days} days ago`;

    const months = Math.floor(days / 30);
    if (months < 12) return `${months} months ago`;

    const years = Math.floor(months / 12);
    return `${years} years ago`;
  }

  private toPage(value?: string) {
    const page = Number(value);
    return Number.isFinite(page) && page > 0 ? page : 1;
  }

  private toLimit(value?: string) {
    const limit = Number(value);
    if (!Number.isFinite(limit) || limit <= 0) return 10;
    return Math.min(limit, 50);
  }

  // GET /mobile/seeker/saved_jobs?userId=&page=&limit=
  @Public()
  @Get('saved_jobs')
  @ApiOperation({ summary: 'Get saved jobs list for mobile app' })
  @ApiQuery({
    name: 'userId',
    required: true,
    type: String,
    description: 'User ID',
  })
  @ApiQuery({
    name: 'page',
    required: false,
    type: Number,
    description: 'Page number (default: 1)',
  })
  @ApiQuery({
    name: 'limit',
    required: false,
    type: Number,
    description: 'Items per page (default: 10)',
  })
  async getSavedJobs(
    @Query('userId') userId: string,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
  ) {
    try {
      if (!userId) {
        return {
          success: false,
          message: 'userId is required',
          data: {
            favorites: [],
            pagination: { page: 1, limit: 10, total: 0, totalPages: 0 },
          },
        };
      }

      const pageNum = this.toPage(page);
      const limitNum = this.toLimit(limit);

      this.logger.log(
        `Mobile saved jobs request - userId: ${userId}, page: ${pageNum}, limit: ${limitNum}`,
      );

      const result = await this.dashboardService.getSeekerFavoriteJobs(userId, {
        page: pageNum,
        limit: limitNum,
      });

      if (result && result.success && result.data && result.data.favorites) {
        let savedJobs = result.data.favorites;
        if (savedJobs.length > 0) {
          const jobIds = savedJobs.map((job: any) => job.job_id).filter(Boolean);
          if (jobIds.length > 0) {
            const jobDataRaw = await this.dataSource.query(
              `SELECT jp.id as job_post_id, jp.created_at, s.skill_name as skill_name,
                      exp.level as experience_level_name, exp.duration as experience_duration
               FROM job_posts jp
               LEFT JOIN job_post_skills jps ON jps.job_post_id = jp.id 
               LEFT JOIN skills s ON jps.skill_id = s.id 
               LEFT JOIN experiences exp ON exp.id = jp.experience_id
               WHERE jp.id IN (?)`,
              [jobIds],
            );
            const skillsByJob = jobDataRaw.reduce((acc: any, curr: any) => {
              if (!acc[curr.job_post_id]) {
                acc[curr.job_post_id] = {
                  skills: [],
                  created_at: curr.created_at,
                  experience_level_name: curr.experience_level_name,
                  experience_duration: curr.experience_duration,
                };
              }
              if (curr.skill_name) {
                acc[curr.job_post_id].skills.push(curr.skill_name);
              }
              return acc;
            }, {});
            savedJobs.forEach((job: any) => {
              const jobData = skillsByJob[job.job_id] || {
                skills: [],
                created_at: null,
                experience_level_name: null,
                experience_duration: null,
              };
              job.required_skills = jobData.skills;
              job.posted_ago = this.getTimeAgoString(jobData.created_at);
              job.experience_level = jobData.experience_duration
                ? `${jobData.experience_level_name} (${jobData.experience_duration})`
                : jobData.experience_level_name || 'Any Experience';
              delete job.skills;
            });
          }
        }
      }

      return result;
    } catch (error) {
      this.logger.error(
        `Failed to fetch saved jobs for userId ${userId}`,
        error instanceof Error ? error.stack : String(error),
      );
      throw new InternalServerErrorException('Unable to fetch saved jobs');
    }
  }

  // POST /mobile/seeker/saved_jobs/bookmark
  @Public()
  @Post('saved_jobs/bookmark')
  @ApiOperation({ summary: 'Save/bookmark a job using userId + jobPostId' })
  async bookmarkJob(@Body() body: { userId?: string; jobPostId?: string }) {
    const userId = body?.userId;
    const jobPostId = body?.jobPostId;

    try {
      if (!userId || !jobPostId) {
        return { success: false, message: 'userId and jobPostId are required' };
      }

      return await this.dashboardService.saveJob(userId, String(jobPostId));
    } catch (error) {
      this.logger.error(
        `Failed to bookmark job - userId: ${userId}, jobPostId: ${jobPostId}`,
        error instanceof Error ? error.stack : String(error),
      );
      throw new InternalServerErrorException('Unable to bookmark job');
    }
  }

  // DELETE /mobile/seeker/saved_jobs/unbookmark?userId=&jobPostId=
  @Public()
  @Delete('saved_jobs/unbookmark')
  @ApiOperation({
    summary: 'Unsave/remove bookmark from a job using userId + jobPostId',
  })
  async unbookmarkJob(
    @Query('userId') userId: string,
    @Query('jobPostId') jobPostId: string,
  ) {
    try {
      if (!userId || !jobPostId) {
        return { success: false, message: 'userId and jobPostId are required' };
      }

      return await this.dashboardService.unbookmarkJob(userId, jobPostId);
    } catch (error) {
      this.logger.error(
        `Failed to unbookmark job - userId: ${userId}, jobPostId: ${jobPostId}`,
        error instanceof Error ? error.stack : String(error),
      );
      throw new InternalServerErrorException('Unable to unbookmark job');
    }
  }

  // GET /mobile/seeker/saved_jobs/is_bookmarked?userId=&jobPostId=
  @Public()
  @Get('saved_jobs/is_bookmarked')
  @ApiOperation({ summary: 'Check whether a job is bookmarked' })
  @ApiQuery({
    name: 'userId',
    required: true,
    type: Number,
    description: 'User ID',
  })
  @ApiQuery({
    name: 'jobPostId',
    required: true,
    type: String,
    description: 'Job Post ID',
  })
  async isBookmarked(
    @Query('userId') userId: string,
    @Query('jobPostId') jobPostId: string,
  ) {
    try {
      if (!userId || !jobPostId) {
        return {
          isBookmarked: false,
          message: 'userId and jobPostId are required',
        };
      }

      return await this.dashboardService.isJobBookmarked(userId, jobPostId);
    } catch (error) {
      this.logger.error(
        `Failed to check bookmark - userId: ${userId}, jobPostId: ${jobPostId}`,
        error instanceof Error ? error.stack : String(error),
      );
      throw new InternalServerErrorException('Unable to check bookmark status');
    }
  }
}
