import {
  BadRequestException,
  Body,
  Controller,
  Get,
  Patch,
  Req,
  UnauthorizedException,
  UploadedFile,
  UseGuards,
  UseInterceptors,
} from '@nestjs/common';

import { FileInterceptor } from '@nestjs/platform-express';

import type { Request } from 'express';

import { randomUUID } from 'crypto';

import { mkdirSync } from 'fs';

import { extname, join } from 'path';

import { diskStorage } from 'multer';

import { JwtAuthGuard } from '@/modules/auth/jwt-auth.guard';

import { UpdateMyOrganizationDto } from './dto/update-my-organization.dto';

import { MyOrganizationService } from './my-organization.service';

type AuthenticatedRequest = Request & {
  user?: {
    id?: number | string;
    userId?: number | string;
    sub?: number | string;
  };
};

type UploadedLogoFile = {
  fieldname: string;
  originalname: string;
  encoding: string;
  mimetype: string;
  destination: string;
  filename: string;
  path: string;
  size: number;
};

// ============================================================
// ORGANIZATION LOGO DIRECTORY
// ============================================================

const ORGANIZATION_LOGO_DIR = join(process.cwd(), 'uploads', 'stakeholders');

// ============================================================
// SYSTEM LOGO DIRECTORY
// ============================================================

const SYSTEM_LOGO_DIR = join(process.cwd(), 'uploads', 'system-logos');

// ============================================================
// CREATE DIRECTORIES
// ============================================================

mkdirSync(ORGANIZATION_LOGO_DIR, {
  recursive: true,
});

mkdirSync(SYSTEM_LOGO_DIR, {
  recursive: true,
});

// ============================================================
// ALLOWED IMAGE TYPES
// ============================================================

const ALLOWED_IMAGE_TYPES = ['image/jpeg', 'image/png', 'image/webp'];

// ============================================================
// GET FILE EXTENSION
// ============================================================

function getLogoExtension(originalName: string, mimeType: string): string {
  const extension = extname(originalName).toLowerCase();

  const allowedExtensions = ['.jpg', '.jpeg', '.png', '.webp'];

  if (allowedExtensions.includes(extension)) {
    return extension;
  }

  if (mimeType === 'image/png') {
    return '.png';
  }

  if (mimeType === 'image/webp') {
    return '.webp';
  }

  if (mimeType === 'image/jpeg') {
    return '.jpg';
  }

  return '.jpg';
}

@UseGuards(JwtAuthGuard)
@Controller('my-organization')
export class MyOrganizationController {
  constructor(private readonly myOrganizationService: MyOrganizationService) {}

  // ============================================================
  // GET MY ORGANIZATION
  // ============================================================

  @Get()
  getMyOrganization(
    @Req()
    request: AuthenticatedRequest,
  ) {
    const userId = this.getCurrentUserId(request);

    return this.myOrganizationService.findMyOrganization(userId);
  }

  // ============================================================
  // UPDATE ORGANIZATION INFORMATION
  // ============================================================

  @Patch()
  updateMyOrganization(
    @Req()
    request: AuthenticatedRequest,

    @Body()
    dto: UpdateMyOrganizationDto,
  ) {
    const userId = this.getCurrentUserId(request);

    return this.myOrganizationService.updateMyOrganization(userId, dto);
  }

  // ============================================================
  // UPDATE ORGANIZATION LOGO
  //
  // PATCH /api/v1/my-organization/logo
  //
  // POSTMAN:
  // Body -> form-data
  // key: logo
  // type: File
  // ============================================================

  @Patch('logo')
  @UseInterceptors(
    FileInterceptor('logo', {
      storage: diskStorage({
        destination: (_request, _file, callback) => {
          callback(null, ORGANIZATION_LOGO_DIR);
        },

        filename: (_request, file, callback) => {
          const extension = getLogoExtension(file.originalname, file.mimetype);

          const fileName = `${Date.now()}-${randomUUID()}${extension}`;

          callback(null, fileName);
        },
      }),

      limits: {
        fileSize: 5 * 1024 * 1024,
      },

      fileFilter: (_request, file, callback) => {
        if (!ALLOWED_IMAGE_TYPES.includes(file.mimetype)) {
          callback(
            new BadRequestException('Logo must be JPG, JPEG, PNG or WEBP.'),
            false,
          );

          return;
        }

        callback(null, true);
      },
    }),
  )
  updateLogo(
    @Req()
    request: AuthenticatedRequest,

    @UploadedFile()
    file?: UploadedLogoFile,
  ) {
    if (!file) {
      throw new BadRequestException('Organization logo file is required.');
    }

    const userId = this.getCurrentUserId(request);

    const logoPath = `/uploads/stakeholders/${file.filename}`;

    return this.myOrganizationService.updateLogo(userId, logoPath);
  }

  // ============================================================
  // UPDATE SYSTEM LOGO
  //
  // PATCH /api/v1/my-organization/system-logo
  //
  // POSTMAN:
  // Body -> form-data
  // key: systemLogo
  // type: File
  // ============================================================

  @Patch('system-logo')
  @UseInterceptors(
    FileInterceptor('systemLogo', {
      storage: diskStorage({
        destination: (_request, _file, callback) => {
          callback(null, SYSTEM_LOGO_DIR);
        },

        filename: (_request, file, callback) => {
          const extension = getLogoExtension(file.originalname, file.mimetype);

          const fileName = `${Date.now()}-${randomUUID()}${extension}`;

          callback(null, fileName);
        },
      }),

      limits: {
        fileSize: 5 * 1024 * 1024,
      },

      fileFilter: (_request, file, callback) => {
        if (!ALLOWED_IMAGE_TYPES.includes(file.mimetype)) {
          callback(
            new BadRequestException(
              'System logo must be JPG, JPEG, PNG or WEBP.',
            ),
            false,
          );

          return;
        }

        callback(null, true);
      },
    }),
  )
  updateSystemLogo(
    @Req()
    request: AuthenticatedRequest,

    @UploadedFile()
    file?: UploadedLogoFile,
  ) {
    if (!file) {
      throw new BadRequestException('System logo file is required.');
    }

    const userId = this.getCurrentUserId(request);

    const systemLogoPath = `/uploads/system-logos/${file.filename}`;

    return this.myOrganizationService.updateSystemLogo(userId, systemLogoPath);
  }

  // ============================================================
  // GET CURRENT LOGIN USER ID
  // ============================================================

  private getCurrentUserId(request: AuthenticatedRequest): number {
    const rawUserId =
      request.user?.id ?? request.user?.userId ?? request.user?.sub;

    const userId = Number(rawUserId);

    if (!Number.isInteger(userId) || userId <= 0) {
      throw new UnauthorizedException('Invalid authenticated user.');
    }

    return userId;
  }
}
