import {
  Controller,
  Get,
  Post,
  Query,
  UseGuards,
  Res,
  BadRequestException,
  InternalServerErrorException,
  ForbiddenException,
} from '@nestjs/common';
import { Response } from 'express';
import { ConfigService } from '@nestjs/config';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import { User } from '../../entities/user.entity';
import { PlatformSettings } from '../../entities/platform-settings.entity';
import { SlackService } from './slack.service';

@Controller('api/slack')
export class SlackController {
  private readonly slackClientId: string;
  private readonly slackClientSecret: string;
  private readonly slackRedirectUri: string;

  constructor(
    private configService: ConfigService,
    private slackService: SlackService,
    @InjectRepository(User)
    private userRepo: Repository<User>,
    @InjectRepository(PlatformSettings)
    private settingsRepo: Repository<PlatformSettings>,
  ) {
    this.slackClientId = this.configService.getOrThrow<string>('SLACK_CLIENT_ID');
    this.slackClientSecret = this.configService.getOrThrow<string>('SLACK_CLIENT_SECRET');
    
    const isLocal = process.env.NODE_ENV !== 'production' && (!process.env.FRONTEND_URL || process.env.FRONTEND_URL.includes('localhost'));
    const defaultFrontendUrl = isLocal ? 'http://localhost:5173' : 'https://deployhub.workzy.co';
    let frontendUrl = (this.configService.get<string>('FRONTEND_URL') || defaultFrontendUrl).trim();
    if (frontendUrl.endsWith('/')) frontendUrl = frontendUrl.slice(0, -1);
    
    this.slackRedirectUri = `${frontendUrl}/settings/slack/callback`;
  }

  /**
   * Initiate Slack OAuth flow
   * Returns the authorization URL to redirect the user to
   */
  @Get('connect')
  @UseGuards(JwtAuthGuard)
  async getConnectUrl(@CurrentUser() user: User) {
    // Check if Slack is enabled for this user
    const isEnabled = await this.slackService.isSlackEnabledForUser(user, this.settingsRepo);
    if (!isEnabled) {
      throw new ForbiddenException('Slack integration is not enabled for your account. Please contact your administrator.');
    }

    const state = Buffer.from(JSON.stringify({ userId: user.id, timestamp: Date.now() })).toString('base64');
    
    const params = new URLSearchParams({
      client_id: this.slackClientId,
      scope: 'incoming-webhook',
      redirect_uri: this.slackRedirectUri,
      state,
    });

    const authUrl = `https://slack.com/oauth/v2/authorize?${params.toString()}`;

    return {
      authUrl,
      redirectUri: this.slackRedirectUri,
    };
  }

  /**
   * Handle Slack OAuth callback
   * This will be called by your frontend after Slack redirects back
   */
  @Post('callback')
  @UseGuards(JwtAuthGuard)
  async handleCallback(
    @CurrentUser() user: User,
    @Query('code') code: string,
    @Query('state') state: string,
  ) {
    if (!code) {
      throw new BadRequestException('No authorization code provided');
    }

    try {
      // Verify state
      const stateData = JSON.parse(Buffer.from(state, 'base64').toString());
      if (stateData.userId !== user.id) {
        throw new BadRequestException('Invalid state parameter');
      }

      // Exchange code for access token
      const tokenResponse = await fetch('https://slack.com/api/oauth.v2.access', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: new URLSearchParams({
          client_id: this.slackClientId,
          client_secret: this.slackClientSecret,
          code,
          redirect_uri: this.slackRedirectUri,
        }),
      });

      if (!tokenResponse.ok) {
        throw new InternalServerErrorException('Failed to exchange code for token');
      }

      const tokenData = await tokenResponse.json();

      if (!tokenData.ok) {
        throw new InternalServerErrorException(`Slack OAuth error: ${tokenData.error}`);
      }

      // Save webhook URL and workspace info
      user.slackWebhookUrl = tokenData.incoming_webhook?.url || null;
      user.slackChannelId = tokenData.incoming_webhook?.channel_id || null;
      user.slackWorkspaceId = tokenData.team?.id || null;
      user.slackAccessToken = tokenData.access_token || null;
      user.slackBotUserId = tokenData.bot_user_id || null;

      await this.userRepo.save(user);

      // Send test notification
      if (user.slackWebhookUrl) {
        await this.slackService.sendTestNotification(user);
      }

      return {
        success: true,
        channelName: tokenData.incoming_webhook?.channel,
        workspaceName: tokenData.team?.name,
      };
    } catch (error) {
      console.error('Slack OAuth callback error:', error);
      throw new InternalServerErrorException(
        error instanceof Error ? error.message : 'Failed to connect Slack',
      );
    }
  }

  /**
   * Disconnect Slack integration
   */
  @Post('disconnect')
  @UseGuards(JwtAuthGuard)
  async disconnect(@CurrentUser() user: User) {
    await this.slackService.disconnectUserSlack(user);
    await this.userRepo.save(user);

    return {
      success: true,
      message: 'Slack disconnected successfully',
    };
  }

  /**
   * Get Slack connection status
   */
  @Get('status')
  @UseGuards(JwtAuthGuard)
  async getStatus(@CurrentUser() user: User) {
    const isEnabled = await this.slackService.isSlackEnabledForUser(user, this.settingsRepo);
    const isConnected = this.slackService.isUserSlackConfigured(user);

    return {
      enabled: isEnabled,
      connected: isConnected,
      channelId: user.slackChannelId,
      workspaceId: user.slackWorkspaceId,
    };
  }

  /**
   * Send test notification
   */
  @Post('test')
  @UseGuards(JwtAuthGuard)
  async sendTest(@CurrentUser() user: User) {
    const result = await this.slackService.sendTestNotification(user);
    
    return {
      success: result,
      message: result
        ? 'Test notification sent successfully! Check your Slack channel.'
        : 'Slack not configured. Please connect your Slack workspace first.',
    };
  }
}
