import {
  Controller,
  Post,
  Get,
  Body,
  Query,
  Param,
  Req,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import {
  ActivityLogsService,
  ActivityLogsQueryService,
  JVCompaniesSummaryService,
} from './activity_logs.service';
import { Public } from '../auth/public.decorator';
import { Request } from 'express';
import {
  ApiBearerAuth,
  ApiTags,
  ApiBody,
  ApiParam,
  ApiQuery,
  ApiOperation,
} from '@nestjs/swagger';

@ApiTags('activity')
@ApiBearerAuth('access-token')
@Controller('activity')
export class ActivityLogsController {
  constructor(
    private activityService: ActivityLogsService,
    private activityQueryService: ActivityLogsQueryService,
    private jvSummaryService: JVCompaniesSummaryService,
  ) {}

  // Log single event (PUBLIC - called from frontend)
  @Public()
  @Post('log')
  @ApiOperation({ summary: 'Log Activity' })
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        user_id: { type: 'number' },
        visitor_id: { type: 'string' },
        user_type: {
          type: 'string',
          enum: [
            'guest',
            'seeker',
            'recruiter',
            'admin',
            'franchise',
            'associate',
          ],
        },
        action_type: { type: 'string' },
        action_name: { type: 'string' },
        page_url: { type: 'string' },
        action_details: { type: 'object' },
        job_id: { type: 'number' },
        company_id: { type: 'number' },
        application_id: { type: 'number' },
        status: {
          type: 'string',
          enum: ['success', 'failed', 'cancelled', 'abandoned'],
        },
        error_message: { type: 'string' },
        device_type: { type: 'string', enum: ['mobile', 'tablet', 'desktop'] },
        browser: { type: 'string' },
      },
      required: ['action_type', 'action_name'],
    },
  })
  async log(@Body() body: any, @Req() req: Request) {
    const ip =
      req.headers['x-forwarded-for'] || req.ip || req.connection.remoteAddress;

    return this.activityService.log({
      ...body,
      ipAddress: ip?.toString() || null,
    });
  }

  // Batch logging (PUBLIC - called from frontend)
  @Public()
  @Post('log/batch')
  @ApiOperation({ summary: 'Batch Log Activity' })
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        logs: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              user_id: { type: 'number' },
              visitor_id: { type: 'string' },
              user_type: {
                type: 'string',
                enum: [
                  'guest',
                  'seeker',
                  'recruiter',
                  'admin',
                  'franchise',
                  'associate',
                ],
              },
              action_type: { type: 'string' },
              action_name: { type: 'string' },
              page_url: { type: 'string' },
              action_details: { type: 'object' },
              job_id: { type: 'number' },
              company_id: { type: 'number' },
              application_id: { type: 'number' },
              status: {
                type: 'string',
                enum: ['success', 'failed', 'cancelled', 'abandoned'],
              },
              error_message: { type: 'string' },
              device_type: {
                type: 'string',
                enum: ['mobile', 'tablet', 'desktop'],
              },
              browser: { type: 'string' },
            },
            required: ['action_type', 'action_name'],
          },
        },
      },
      required: ['logs'],
    },
  })
  async logBatch(@Body() body: { logs: any[] }, @Req() req: Request) {
    const ip =
      req.headers['x-forwarded-for'] || req.ip || req.connection.remoteAddress;

    // Add IP to all logs
    const logsWithIp = body.logs.map((log) => ({
      ...log,
      ipAddress: ip?.toString() || null,
    }));

    return this.activityService.logBatch(logsWithIp);
  }

  // Get activity stats (PUBLIC - for admin dashboard)
  @Public()
  @Get('logs')
  @ApiOperation({ summary: 'Get Activity Logs with Filters' })
  @ApiQuery({ name: 'userId', required: false, type: Number })
  @ApiQuery({ name: 'companyId', required: false, type: Number })
  async getLogs(
    @Query('page') page?: number,
    @Query('limit') limit?: number,
    @Query('userType') userType?: string,
    @Query('actionType') actionType?: string, // Comma-separated for multiple
    @Query('from') from?: string,
    @Query('to') to?: string,
    @Query('dateRange') dateRange?: number,
    @Query('userId') userId?: number,
    @Query('companyId') companyId?: number,
    @Query('excludeAdmin') excludeAdmin?: string,
  ) {
    try {
      const actionTypes = actionType
        ? actionType.split(',').map((s) => s.trim())
        : undefined;

      return await this.activityService.getLogs({
        page: page ? Number(page) : 1,
        limit: limit ? Number(limit) : 20,
        userType,
        actionTypes,
        from,
        to,
        dateRange: dateRange ? Number(dateRange) : undefined,
        userId: userId ? Number(userId) : undefined,
        companyId: companyId ? Number(companyId) : undefined,
        excludeAdmin: excludeAdmin === 'true',
      });
    } catch (error) {
      throw new HttpException(
        'Failed to fetch activity logs',
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  @Public()
  @Get('stats')
  @ApiOperation({ summary: 'Get Activity Stats' })
  @ApiQuery({ name: 'dateRange', required: false, type: Number })
  @ApiQuery({ name: 'from', required: false, type: String })
  @ApiQuery({ name: 'to', required: false, type: String })
  async getStats(
    @Query('dateRange') dateRange?: number,
    @Query('from') from?: string,
    @Query('to') to?: string,
  ) {
    return this.activityService.getActivityStats(dateRange, from, to);
  }

  // Get user journey (PUBLIC - for admin dashboard)
  @Public()
  @Get('user/:userId/journey')
  @ApiOperation({ summary: 'Get User Journey' })
  @ApiParam({ name: 'userId', type: Number })
  @ApiQuery({ name: 'limit', required: false, type: Number })
  async getUserJourney(
    @Param('userId') userId: number,
    @Query('limit') limit: number = 50,
  ) {
    return this.activityService.getUserJourney(userId, limit);
  }

  // Get guest journey (PUBLIC - for admin dashboard)
  @Public()
  @Get('guest/:visitorId/journey')
  @ApiOperation({ summary: 'Get Guest Journey' })
  @ApiParam({ name: 'visitorId', type: String })
  @ApiQuery({ name: 'limit', required: false, type: Number })
  async getGuestJourney(
    @Param('visitorId') visitorId: string,
    @Query('limit') limit: number = 50,
  ) {
    return this.activityService.getGuestJourney(visitorId, limit);
  }

  // Get popular pages (PUBLIC - for admin dashboard)
  @Public()
  @Get('popular-pages')
  @ApiOperation({ summary: 'Get Popular Pages' })
  @ApiQuery({ name: 'dateRange', required: false, type: Number })
  @ApiQuery({ name: 'limit', required: false, type: Number })
  @ApiQuery({ name: 'from', required: false, type: String })
  @ApiQuery({ name: 'to', required: false, type: String })
  async getPopularPages(
    @Query('dateRange') dateRange?: number,
    @Query('limit') limit: number = 20,
    @Query('from') from?: string,
    @Query('to') to?: string,
  ) {
    return this.activityService.getPopularPages(dateRange, limit, from, to);
  }

  // Get conversion funnel (PUBLIC - for admin dashboard)
  @Public()
  @Get('funnel/:type')
  @ApiOperation({ summary: 'Get Conversion Funnel' })
  @ApiParam({ name: 'type', type: String })
  @ApiQuery({ name: 'dateRange', required: false, type: Number })
  @ApiQuery({ name: 'from', required: false, type: String })
  @ApiQuery({ name: 'to', required: false, type: String })
  async getConversionFunnel(
    @Param('type') type: string,
    @Query('dateRange') dateRange?: number,
    @Query('from') from?: string,
    @Query('to') to?: string,
  ) {
    return this.activityService.getConversionFunnel(
      type,
      dateRange ? Number(dateRange) : undefined,
      from,
      to,
    );
  }

  // Get abandoned applications with phone numbers (PUBLIC - for admin dashboard)
  @Public()
  @Get('abandoned-applications')
  @ApiOperation({ summary: 'Get Abandoned Applications' })
  @ApiQuery({ name: 'dateRange', required: false, type: Number })
  @ApiQuery({ name: 'from', required: false, type: String })
  @ApiQuery({ name: 'to', required: false, type: String })
  async getAbandonedApplications(
    @Query('dateRange') dateRange?: number,
    @Query('from') from?: string,
    @Query('to') to?: string,
  ) {
    return this.activityService.getAbandonedApplications(dateRange, from, to);
  }

  // Get failed OTP attempts (PUBLIC - for admin dashboard)
  @Public()
  @Get('failed-otp')
  @ApiOperation({ summary: 'Get Failed OTP Attempts' })
  @ApiQuery({ name: 'dateRange', required: false, type: Number })
  @ApiQuery({ name: 'from', required: false, type: String })
  @ApiQuery({ name: 'to', required: false, type: String })
  async getFailedOTPAttempts(
    @Query('dateRange') dateRange?: number,
    @Query('from') from?: string,
    @Query('to') to?: string,
  ) {
    return this.activityService.getFailedOTPAttempts(dateRange, from, to);
  }

  // Get IP-wise statistics (PUBLIC - for admin dashboard)
  @Public()
  @Get('ip-statistics')
  @ApiOperation({ summary: 'Get IP Statistics' })
  @ApiQuery({ name: 'dateRange', required: false, type: Number })
  @ApiQuery({ name: 'from', required: false, type: String })
  @ApiQuery({ name: 'to', required: false, type: String })
  async getIpStatistics(
    @Query('dateRange') dateRange?: number,
    @Query('from') from?: string,
    @Query('to') to?: string,
  ) {
    return this.activityService.getIpWiseStatistics(dateRange, from, to);
  }

  // Get security/access logs (PUBLIC - for admin dashboard)
  @Public()
  @Get('security-logs')
  @ApiOperation({ summary: 'Get Security Logs' })
  @ApiQuery({ name: 'dateRange', required: false, type: Number })
  @ApiQuery({ name: 'from', required: false, type: String })
  @ApiQuery({ name: 'to', required: false, type: String })
  async getSecurityLogs(
    @Query('dateRange') dateRange?: number,
    @Query('from') from?: string,
    @Query('to') to?: string,
  ) {
    return this.activityService.getSecurityLogs(dateRange, from, to);
  }

  // Get page time statistics (PUBLIC - for admin dashboard)
  @Public()
  @Get('page-time')
  @ApiOperation({ summary: 'Get Page Time Stats' })
  @ApiQuery({ name: 'dateRange', required: false, type: Number })
  @ApiQuery({ name: 'from', required: false, type: String })
  @ApiQuery({ name: 'to', required: false, type: String })
  async getPageTime(
    @Query('dateRange') dateRange?: number,
    @Query('from') from?: string,
    @Query('to') to?: string,
  ) {
    return this.activityService.getPageTimeStats(dateRange, from, to);
  }

  // Role-wise analytics tables (PUBLIC - for admin logger analytics dashboard)
  @Public()
  @Get('analytics/recruiters')
  @ApiOperation({ summary: 'Get Recruiter Analytics' })
  async getRecruiterAnalytics(@Query() query: any) {
    return this.activityService.getRecruiterActivity(query);
  }

  @Public()
  @Get('analytics/agents')
  @ApiOperation({ summary: 'Get Agent Analytics' })
  async getAgentAnalytics(@Query() query: any) {
    return this.activityService.getAgentActivity(query);
  }

  @Public()
  @Get('analytics/seekers')
  @ApiOperation({ summary: 'Get Seeker Analytics' })
  async getSeekerAnalytics(@Query() query: any) {
    return this.activityService.getSeekerActivity(query);
  }

  // JV Companies summary (PUBLIC)
  @Public()
  @Get('analytics/jv-companies')
  @ApiOperation({ summary: 'Get JV Companies Summary' })
  @ApiQuery({ name: 'from', required: false, type: String })
  @ApiQuery({ name: 'to', required: false, type: String })
  @ApiQuery({ name: 'companyId', required: false, type: String })
  async getJVCompanies(
    @Query('from') from?: string,
    @Query('to') to?: string,
    @Query('companyId') companyId?: string,
  ) {
    const cid = companyId ? Number(companyId) : undefined;
    return this.jvSummaryService.getJVCompaniesSummary({
      from,
      to,
      companyId: cid,
    });
  }
}
