import {
  Controller,
  Post,
  Get,
  Delete,
  Body,
  Param,
  Headers,
  UseGuards,
  Request,
  Logger,
  Patch,
  Res,
} from '@nestjs/common';
import { Response } from 'express';
import { FeishuService } from './feishu.service';
import { FeishuAssessmentService } from './services/feishu-assessment.service';
import { CreateFeishuBotDto } from './dto/create-bot.dto';
import { CombinedAuthGuard } from '../auth/combined-auth.guard';
import { Public } from '../auth/public.decorator';
import * as fs from 'fs';
import * as path from 'path';

@Controller('feishu')
export class FeishuController {
  private readonly logger = new Logger(FeishuController.name);

  constructor(
    private readonly feishuService: FeishuService,
    private readonly feishuAssessmentService: FeishuAssessmentService,
  ) {}

  // ─── Bot Management Endpoints (JWT-protected) ─────────────────────────────

  /** GET /feishu/bots - List user's bots, masking sensitive fields */
  @Get('bots')
  @UseGuards(CombinedAuthGuard)
  async listBots(@Request() req) {
    const bots = await this.feishuService.getUserBots(req.user.id);
    return bots.map((bot) => ({
      id: bot.id,
      appId: bot.appId,
      botName: bot.botName,
      enabled: bot.enabled,
      isDefault: bot.isDefault,
      webhookUrl: `/api/feishu/webhook/${bot.appId}`,
      createdAt: bot.createdAt,
    }));
  }

  /** POST /feishu/bots - Create or update a bot */
  @Post('bots')
  @UseGuards(CombinedAuthGuard)
  async createBot(@Request() req, @Body() dto: CreateFeishuBotDto) {
    const bot = await this.feishuService.createBot(req.user.id, dto);
    return {
      id: bot.id,
      appId: bot.appId,
      botName: bot.botName,
      enabled: bot.enabled,
      webhookUrl: `/api/feishu/webhook/${bot.appId}`,
    };
  }

  /** PATCH /feishu/bots/:id/toggle - Enable or disable a bot */
  @Patch('bots/:id/toggle')
  @UseGuards(CombinedAuthGuard)
  async toggleBot(
    @Request() req,
    @Param('id') botId: string,
    @Body() body: { enabled: boolean },
  ) {
    const bot = await this.feishuService.setBotEnabled(botId, body.enabled);
    return { id: bot.id, enabled: bot.enabled };
  }

  /** DELETE /feishu/bots/:id - Delete a bot */
  @Delete('bots/:id')
  @UseGuards(CombinedAuthGuard)
  async deleteBot(@Request() req, @Param('id') botId: string) {
    await this.feishuService.deleteBot(req.user.id, botId);
    return { success: true };
  }

  // ─── WebSocket Management Endpoints ────────────────────────────────────

  /** POST /feishu/bots/:id/ws/connect - Start WebSocket connection */
  @Post('bots/:id/ws/connect')
  @UseGuards(CombinedAuthGuard)
  async connectWs(@Request() req, @Param('id') botId: string) {
    const bot = await this.feishuService.getBotById(botId);
    if (!bot || bot.userId !== req.user.id) {
      return { success: false, error: 'Bot not found' };
    }
    try {
      await this.feishuService.startWsConnection(botId);
      return { success: true, botId, status: 'connecting' };
    } catch (error: any) {
      return {
        success: false,
        botId,
        error: error?.message || 'Failed to connect',
      };
    }
  }

  /** POST /feishu/bots/:id/ws/disconnect - Stop WebSocket connection */
  @Post('bots/:id/ws/disconnect')
  @UseGuards(CombinedAuthGuard)
  async disconnectWs(@Request() req, @Param('id') botId: string) {
    const bot = await this.feishuService.getBotById(botId);
    if (!bot || bot.userId !== req.user.id) {
      return { success: false, error: 'Bot not found' };
    }
    try {
      await this.feishuService.stopWsConnection(botId);
      return { success: true, botId, status: 'disconnected' };
    } catch (error: any) {
      return {
        success: false,
        botId,
        error: error?.message || 'Failed to disconnect',
      };
    }
  }

  /** GET /feishu/bots/:id/ws/status - Get connection status */
  @Get('bots/:id/ws/status')
  @UseGuards(CombinedAuthGuard)
  async getWsStatus(@Request() req, @Param('id') botId: string) {
    const bot = await this.feishuService.getBotById(botId);
    if (!bot || bot.userId !== req.user.id) {
      return { success: false, error: 'Bot not found' };
    }
    const status = await this.feishuService.getWsStatus(botId);
    if (!status) {
      return { botId, state: 'disconnected' };
    }
    return {
      botId: status.botId,
      state: status.state,
      connectedAt: status.connectedAt?.toISOString(),
      lastHeartbeat: status.lastHeartbeat?.toISOString(),
      error: status.error,
    };
  }

  /** GET /feishu/ws/status - Get all active WS connection statuses */
  @Get('ws/status')
  @UseGuards(CombinedAuthGuard)
  async getAllWsStatus() {
    const statuses = await this.feishuService.getAllWsStatuses();
    return {
      connections: statuses.map((s) => ({
        botId: s.botId,
        state: s.state,
        connectedAt: s.connectedAt?.toISOString(),
        lastHeartbeat: s.lastHeartbeat?.toISOString(),
        error: s.error,
      })),
    };
  }

  // ─── Feishu Webhook Endpoint (Public) ────────────────────────────────────
  @Get('webhook/:appId')
  @Post('webhook/:appId')
  @Public()
  async handleWebhook(
    @Param('appId') appId: string,
    @Body() body: any,
    @Headers() headers: any,
    @Request() req: any,
    @Res() res: Response,
  ) {
    const logEntry = `\n[${new Date().toISOString()}] ${req.method} /api/feishu/webhook/${appId}\nHeaders: ${JSON.stringify(headers)}\nBody: ${JSON.stringify(body)}\n`;
    fs.appendFileSync('feishu_webhook.log', logEntry);

    this.logger.log(
      `Incoming Feishu webhook [${req.method}] for appId: ${appId}`,
    );

    // GET request for simple connection test
    if (req.method === 'GET') {
      return res.status(200).json({
        status: 'ok',
        message: 'AuraK Feishu Webhook is active.',
        appId,
        timestamp: new Date().toISOString(),
      });
    }

    // Step 1: URL verification handshake
    const challenge = body?.challenge || body?.event?.challenge;
    if (body?.type === 'url_verification' || challenge) {
      this.logger.log(
        `URL verification active for appId: ${appId}, challenge: ${challenge}`,
      );
      return res.status(200).json({ challenge });
    }

    // Step 2: Return 200 immediately for all other events
    res.status(200).json({ success: true });

    // Step 3: Process the event asynchronously
    if (body?.type === 'event_callback' || body?.header?.event_type) {
      setImmediate(() =>
        this._processEvent(appId, body).catch((e) =>
          this.logger.error('Failed to process Feishu event async', e),
        ),
      );
    }
  }

  // ─── Private Event Processor ─────────────────────────────────────────────

  private async _processEvent(appId: string, body: any): Promise<void> {
    const { type, event, header } = body;

    if (type !== 'event_callback') return;

    const eventType = header?.event_type || body.event_type;
    const eventId = header?.event_id;
    this.logger.log(
      `Processing Feishu event [${eventId}]: ${eventType} for appId: ${appId}`,
    );

    const bot = await this.feishuService.getBotByAppId(appId);
    if (!bot || !bot.enabled) {
      this.logger.warn(`Bot not found or disabled for appId: ${appId}`);
      return;
    }

    switch (eventType) {
      case 'im.message.receive_v1':
      case 'im.message.p2p_msg_received':
      case 'im.message.group_at_msg_received':
        await this._handleMessage(bot, event);
        break;
      default:
        this.logger.log(`Unhandled event type: ${eventType}`);
    }
  }

  /**
   * Parse incoming IM message and route to chatService via FeishuService.
   * Implements Chunk 5 integration.
   */
  private async _handleMessage(bot: any, event: any): Promise<void> {
    const message = event?.message;
    if (!message) return;

    const messageId = message.message_id;
    const openId = event?.sender?.sender_id?.open_id;

    if (!openId) {
      this.logger.warn('No sender open_id found in Feishu event');
      return;
    }

    // Parse text content
    let userText = '';
    try {
      const content = JSON.parse(message.content || '{}');
      userText = content.text || '';
    } catch {
      this.logger.warn('Failed to parse Feishu message content');
      return;
    }

    if (!userText.trim()) return;

    try {
      // Centralized routing via FeishuService
      await this.feishuService.handleIncomingMessage(
        bot,
        openId,
        messageId,
        userText,
      );
    } catch (error) {
      this.logger.error('Message handling failed', error);
    }
  }
}
