import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Param,
  Body,
  Headers,
  UnauthorizedException,
  NotFoundException,
  BadRequestException,
  HttpCode,
  HttpStatus,
} from '@nestjs/common';
import { ChannelRepository } from '../../../infrastructure/repositories/channel.repository';
import * as jwt from 'jsonwebtoken';

/**
 * Notification channel management.
 * Admin endpoints: POST/PUT/DELETE require platform_admin role.
 * Public GET (list channels) is accessible to any authenticated user (for preferences UI).
 */
@Controller('api/v1/notifications/channels')
export class NotificationChannelController {
  constructor(private readonly repo: ChannelRepository) {}

  /** GET /api/v1/notifications/channels — list all enabled channels */
  @Get()
  async listChannels(@Headers('authorization') auth: string) {
    this.extractUser(auth); // any valid JWT
    return this.repo.listChannels();
  }

  /** POST /api/v1/notifications/channels — create channel (admin only) */
  @Post()
  async createChannel(
    @Headers('authorization') auth: string,
    @Body() body: { channelKey: string; name: string; description?: string; isMandatory?: boolean },
  ) {
    this.requireAdmin(auth);
    if (!body.channelKey?.match(/^[a-z0-9_]+$/)) {
      throw new BadRequestException('channelKey must be lowercase alphanumeric with underscores');
    }
    return this.repo.createChannel(body);
  }

  /** PUT /api/v1/notifications/channels/:key — update channel (admin only) */
  @Put(':key')
  async updateChannel(
    @Headers('authorization') auth: string,
    @Param('key') key: string,
    @Body() body: { name?: string; description?: string; isMandatory?: boolean; isEnabled?: boolean },
  ) {
    this.requireAdmin(auth);
    const result = await this.repo.updateChannel(key, body);
    if (!result) throw new NotFoundException('Channel not found');
    return result;
  }

  /** DELETE /api/v1/notifications/channels/:key — delete channel (admin only) */
  @Delete(':key')
  @HttpCode(HttpStatus.NO_CONTENT)
  async deleteChannel(
    @Headers('authorization') auth: string,
    @Param('key') key: string,
  ) {
    this.requireAdmin(auth);
    await this.repo.deleteChannel(key);
  }

  // ── User preferences ──────────────────────────────────────────────────────

  /** GET /api/v1/notifications/channels/me/preferences */
  @Get('me/preferences')
  async getMyPreferences(@Headers('authorization') auth: string) {
    const { userId } = this.extractUser(auth);
    return this.repo.getUserPreferences(userId);
  }

  /** PUT /api/v1/notifications/channels/me/preferences — bulk update user preferences */
  @Put('me/preferences')
  async updateMyPreferences(
    @Headers('authorization') auth: string,
    @Body() body: { preferences: { channelKey: string; enabled: boolean }[] },
  ) {
    const { userId } = this.extractUser(auth);
    await this.repo.setAllUserPreferences(userId, body.preferences ?? []);
    return { ok: true };
  }

  /** PUT /api/v1/notifications/channels/me/preferences/:key — update single preference */
  @Put('me/preferences/:key')
  async updateOnePreference(
    @Headers('authorization') auth: string,
    @Param('key') key: string,
    @Body() body: { enabled: boolean },
  ) {
    const { userId } = this.extractUser(auth);
    try {
      await this.repo.setUserPreference(userId, key, body.enabled);
    } catch (e: any) {
      throw new BadRequestException(e.message);
    }
    return { ok: true };
  }

  private extractUser(auth: string): { userId: string } {
    if (!auth?.startsWith('Bearer ')) throw new UnauthorizedException('Missing authorization header');
    const token = auth.slice(7);
    try {
      const payload = jwt.verify(token, process.env.JWT_SECRET || 'dev-secret') as any;
      return { userId: payload.sub };
    } catch {
      throw new UnauthorizedException('Invalid JWT');
    }
  }

  private requireAdmin(auth: string): void {
    if (!auth?.startsWith('Bearer ')) throw new UnauthorizedException('Missing authorization header');
    const token = auth.slice(7);
    try {
      const payload = jwt.verify(token, process.env.JWT_SECRET || 'dev-secret') as any;
      const roles: string[] = Array.isArray(payload.roles) ? payload.roles : [];
      if (!roles.includes('platform_admin') && !roles.includes('platform_super_admin')) {
        throw new UnauthorizedException('Admin role required');
      }
    } catch (err) {
      if (err instanceof UnauthorizedException) throw err;
      throw new UnauthorizedException('Invalid JWT');
    }
  }
}
