import { Injectable } from '@nestjs/common';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { DataSource, Repository } from 'typeorm';
import { JobViews } from './entities/job_views.entity';
import { ActivityLogsService } from '../activity_logs/activity_logs.service';
import { JobPosts } from '../job_posts/entities/job_posts.entity';

@Injectable()
export class JobViewsService {
  constructor(
    @InjectRepository(JobViews)
    private readonly jobViewsRepository: Repository<JobViews>,
    @InjectRepository(JobPosts)
    private readonly jobPostsRepository: Repository<JobPosts>,
    private readonly activityLogsService: ActivityLogsService,
    @InjectDataSource()
    private dataSource: DataSource,
  ) {}

  async trackJobView(
    jobPostId: number,
    viewerId?: number,
    userRole?: string,
  ): Promise<any> {
    try {
      // console.log('JobViewsService.trackJobView called with:', {
      //   jobPostId,
      //   viewerId,
      //   userRole,
      // });

      // Log Activity to ActivityLogsService (Report 2)
      // We do this BEFORE the skip check because we want to log ALL views for the admin report,
      // even if we skip the internal 'view count' tracking.
      if (viewerId) {
        this.logJobViewActivity(jobPostId, viewerId, userRole).catch((err) =>
          console.error('Background log error:', err),
        );
      }

      // Skip tracking for franchise, recruiter, and admin users (only track job seekers and anonymous users)
      if (
        userRole === 'franchise' ||
        userRole === 'recruiter' ||
        userRole === 'admin' ||
        userRole === 'associate' // Added associate to skip list for consistency with non-seeker tracking
      ) {
        // console.log('Skipping view tracking for non-seeker user:', userRole);
        return {
          success: true,
          message: 'View tracking skipped for non-seeker user',
          data: null,
        };
      }

      const jobView = this.jobViewsRepository.create({
        jobPostId,
        viewerId,
      });

      // console.log('Creating job view record:', {
      //   jobPostId,
      //   viewerId,
      //   isAnonymous: viewerId === undefined || viewerId === null,
      // });

      const result = await this.jobViewsRepository.save(jobView);

      // console.log('Job view saved successfully:', result);

      return {
        success: true,
        message: 'Job view tracked successfully',
        data: result,
      };
    } catch (error) {
      // console.error('Error tracking job view:', error);
      return {
        success: false,
        message: 'Failed to track job view',
        error: error.message,
      };
    }
  }

  async getJobViewsCount(jobPostId: number): Promise<any> {
    try {
      const count = await this.jobViewsRepository.count({
        where: { jobPostId },
      });

      return {
        success: true,
        data: { count },
      };
    } catch (error) {
      return {
        success: false,
        message: 'Failed to get job views count',
        error: error.message,
      };
    }
  }

  async getJobViewsByCompany(companyId: number): Promise<any> {
    try {
      const views = await this.dataSource
        .createQueryBuilder()
        .select('COUNT(*)', 'count')
        .from('job_views', 'jv')
        .innerJoin('job_posts', 'jp', 'jp.id = jv.job_post_id')
        .where('jp.company_id = :companyId', { companyId })
        .getRawOne();

      return {
        success: true,
        data: { count: parseInt(views?.count || '0') },
      };
    } catch (error) {
      return {
        success: false,
        message: 'Failed to get job views by company',
        error: error.message,
      };
    }
  }

  async getJobViewsByFranchise(franchiseId: number): Promise<any> {
    try {
      const views = await this.dataSource
        .createQueryBuilder()
        .select('COUNT(*)', 'count')
        .from('job_views', 'jv')
        .innerJoin('job_posts', 'jp', 'jp.id = jv.job_post_id')
        .innerJoin('companies', 'c', 'c.id = jp.company_id')
        .where('c.franchise_id = :franchiseId', { franchiseId })
        .andWhere('c.is_deleted = 0')
        .getRawOne();

      return {
        success: true,
        data: { count: parseInt(views?.count || '0') },
      };
    } catch (error) {
      return {
        success: false,
        message: 'Failed to get job views by franchise',
        error: error.message,
      };
    }
  }

  async getThisMonthViewsByFranchise(franchiseId: number): Promise<any> {
    try {
      const views = await this.dataSource
        .createQueryBuilder()
        .select('COUNT(*)', 'count')
        .from('job_views', 'jv')
        .innerJoin('job_posts', 'jp', 'jp.id = jv.job_post_id')
        .innerJoin('companies', 'c', 'c.id = jp.company_id')
        .where('c.franchise_id = :franchiseId', { franchiseId })
        .andWhere('c.is_deleted = 0')
        .andWhere('MONTH(jv.viewed_at) = MONTH(NOW())')
        .andWhere('YEAR(jv.viewed_at) = YEAR(NOW())')
        .getRawOne();

      return {
        success: true,
        data: { count: parseInt(views?.count || '0') },
      };
    } catch (error) {
      return {
        success: false,
        message: 'Failed to get this month views by franchise',
        error: error.message,
      };
    }
  }

  async getRecentViewsForJob(jobPostId: number): Promise<any> {
    try {
      const views = await this.jobViewsRepository.find({
        where: { jobPostId },
        order: { viewedAt: 'DESC' },
        take: 10,
      });

      return {
        success: true,
        data: {
          total: views.length,
          views: views.map((view) => ({
            id: view.id,
            jobPostId: view.jobPostId,
            viewerId: view.viewerId,
            viewedAt: view.viewedAt,
            isAnonymous: view.viewerId === null || view.viewerId === undefined,
          })),
        },
      };
    } catch (error) {
      return {
        success: false,
        message: 'Failed to get recent views for job',
        error: error.message,
      };
    }
  }

  private async logJobViewActivity(
    jobPostId: number,
    viewerId: number,
    userRole: string,
  ) {
    try {
      // 1. Fetch Job with Company user_id to check ownership using raw query
      // (JobPosts entity does not have 'company' relation property defined)
      const jobData = await this.dataSource
        .createQueryBuilder()
        .select([
          'job.title AS title',
          'job.company_id AS company_id',
          'job.associate_id AS associate_id',
          'job.city_id AS city_id',
          'company.user_id AS company_user_id',
        ])
        .from('job_posts', 'job')
        .leftJoin('companies', 'company', 'company.id = job.company_id')
        .where('job.id = :id', { id: jobPostId })
        .getRawOne();

      if (!jobData) return;

      // 2. Calculate Flags
      let isOwnCompany = false;
      let postedByThisUser = false;
      let companyId = jobData.company_id;

      if (userRole === 'recruiter') {
        // Recruiter owns the company if company.user_id matches viewerId.
        if (jobData.company_user_id === viewerId) {
          isOwnCompany = true;
        }
        postedByThisUser = isOwnCompany;
      } else if (userRole === 'associate') {
        isOwnCompany = false; // Associate never owns
        // Associate posted this?
        if (jobData.associate_id === viewerId) {
          postedByThisUser = true;
        }
      }

      // 3. Log
      await this.activityLogsService.log({
        userId: viewerId,
        userType: userRole,
        actionType: 'job_view',
        actionName: `Viewed Job: ${jobData.title}`,
        jobId: jobPostId,
        companyId: companyId,
        is_billable: false, // Never billable
        credits_used: 0,
        actionDetails: {
          title: jobData.title,
          is_own_company: isOwnCompany,
          posted_by_this_user: postedByThisUser,
          location: jobData.city_id ? `City ID: ${jobData.city_id}` : 'Unknown',
        },
      });
    } catch (error) {
      console.error('Error logging job view activity:', error);
    }
  }
}
