import { Controller, Get, Post, Patch, Delete, Body, Param, Query, ParseUUIDPipe, HttpCode, HttpStatus, UseInterceptors, UploadedFiles } from '@nestjs/common';
import { AnyFilesInterceptor } from '@nestjs/platform-express';
import { ApiOperation, ApiTags, ApiConsumes } from '@nestjs/swagger';
import { CurrentUser } from '@edr/api-common';
import { FilesService } from '../files/files.service';
import { CompaniesService } from './companies.service';
import { CreateCompanyDto } from './dto/create-company.dto';
import { UpdateCompanyDto } from './dto/update-company.dto';
import { CreateExternalProfileDto } from './dto/create-external-profile.dto';
import { CreateFFClientDto } from './dto/create-ff-client.dto';
import { CreateCompanyWithProfileDto } from './dto/create-company-with-profile.dto';
import { ResponseCompanyDto } from './dto/response-company.dto';
import { ResponseExternalProfileDto } from './dto/response-external-profile.dto';
import { ResponseFFClientDto } from './dto/response-ff-client.dto';
import { CompanyInfoResponseDto } from './dto/company-info-response.dto';
import { UpdateProfileDto } from './dto/update-profile.dto';
import { ProfileResponseDto } from './dto/profile-response.dto';

interface CurrentIamUser {
  id: string;
  name?: { en: string; am: string };
  email?: string;
  phoneNumber?: string;
}

@ApiTags('Companies')
@Controller('companies')
export class CompaniesController {
  constructor(
    private readonly companiesService: CompaniesService,
    private readonly filesService: FilesService,
  ) {}

  @Get('getInfo')
  @ApiOperation({ summary: 'Get company info for the current user' })
  async getInfo(@CurrentUser() user: CurrentIamUser): Promise<CompanyInfoResponseDto> {
    const { profile, company } = await this.companiesService.getCompanyInfoByUserId(user.id);
    return new CompanyInfoResponseDto(profile, company);
  }

  @Get('profile')
  @ApiOperation({ summary: 'Get flattened profile for the settings page' })
  async getProfile(@CurrentUser() user: CurrentIamUser): Promise<ProfileResponseDto> {
    const { profile, company } = await this.companiesService.getCompanyInfoByUserId(user.id);
    return new ProfileResponseDto(profile, company);
  }

  @Patch('profile')
  @ApiOperation({ summary: 'Update profile (flattened settings page)' })
  async updateProfile(
    @CurrentUser() user: CurrentIamUser,
    @Body() dto: UpdateProfileDto,
  ): Promise<ProfileResponseDto> {
    return this.companiesService.updateProfile(user.id, dto);
  }

  @Post('create')
  @ApiOperation({ summary: 'Create a company with its associated external profile (onboarding)' })
  async createWithProfile(
    @CurrentUser() user: CurrentIamUser,
    @Body() dto: CreateCompanyWithProfileDto,
  ): Promise<CompanyInfoResponseDto> {
    const nameParts = (user.name?.en ?? '').split(' ');
    const { profile, company } = await this.companiesService.createCompanyWithProfile(
      {
        userId: user.id,
        firstName: nameParts[0] || '',
        lastName: nameParts.slice(-1)[0] || '',
        email: user.email ?? '',
        phone: user.phoneNumber ?? '',
      },
      dto,
    );
    return new CompanyInfoResponseDto(profile, company);
  }

  @Post()
  @ApiOperation({ summary: 'Create a new company (customer, forwarder, transporter, broker)' })
  async create(@Body() dto: CreateCompanyDto): Promise<ResponseCompanyDto> {
    const company = await this.companiesService.createCompany(dto);
    return new ResponseCompanyDto(company);
  }

  @Get()
  @ApiOperation({ summary: 'List all companies' })
  async findAll(): Promise<ResponseCompanyDto[]> {
    const companies = await this.companiesService.findAllCompanies();
    return companies.map((c) => new ResponseCompanyDto(c));
  }

  @Get('type/:type')
  @ApiOperation({ summary: 'Find companies by type' })
  async findByType(@Param('type') type: string): Promise<ResponseCompanyDto[]> {
    const companies = await this.companiesService.findAllCompanies();
    return companies.filter((c) => c.type === type).map((c) => new ResponseCompanyDto(c));
  }

  @Get('search')
  @ApiOperation({ summary: 'Search companies by name' })
  async search(@Query('name') name: string): Promise<ResponseCompanyDto[]> {
    const companies = await this.companiesService.findAllCompanies();
    return companies
      .filter((c) => c.name.toLowerCase().includes(name.toLowerCase()))
      .map((c) => new ResponseCompanyDto(c));
  }

  @Get(':id')
  @ApiOperation({ summary: 'Get company by ID' })
  async findById(@Param('id', ParseUUIDPipe) id: string): Promise<ResponseCompanyDto> {
    const company = await this.companiesService.findCompanyById(id);
    return new ResponseCompanyDto(company);
  }

  @Patch(':id')
  @ApiOperation({ summary: 'Update a company' })
  async update(
    @Param('id', ParseUUIDPipe) id: string,
    @Body() dto: UpdateCompanyDto,
  ): Promise<ResponseCompanyDto> {
    const company = await this.companiesService.updateCompany(id, dto);
    return new ResponseCompanyDto(company);
  }

  @Delete(':id')
  @ApiOperation({ summary: 'Soft-delete a company' })
  @HttpCode(HttpStatus.NO_CONTENT)
  async remove(@Param('id', ParseUUIDPipe) id: string): Promise<void> {
    await this.companiesService.deleteCompany(id);
  }

  @Post(':companyId/documents')
  @UseInterceptors(AnyFilesInterceptor())
  @ApiConsumes('multipart/form-data')
  @ApiOperation({ summary: 'Upload documents for a company (onboarding)' })
  async uploadDocuments(
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @UploadedFiles() files: Array<Express.Multer.File>,
  ) {
    return this.filesService.uploadMany(companyId, 'companies', files);
  }

  @Post(':companyId/profiles')
  @ApiOperation({ summary: 'Add a profile (employee) to a company' })
  async createProfile(
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @Body() dto: CreateExternalProfileDto,
  ): Promise<ResponseExternalProfileDto> {
    const profile = await this.companiesService.createProfile({ ...dto, companyId });
    return new ResponseExternalProfileDto(profile);
  }

  @Get(':companyId/profiles')
  @ApiOperation({ summary: 'List profiles for a company' })
  async listProfiles(
    @Param('companyId', ParseUUIDPipe) companyId: string,
  ): Promise<ResponseExternalProfileDto[]> {
    const profiles = await this.companiesService.findProfilesByCompany(companyId);
    return profiles.map((p) => new ResponseExternalProfileDto(p));
  }

  @Get('profile/user/:userId')
  @ApiOperation({ summary: 'Get profile by IAM user ID' })
  async findProfileByUser(
    @Param('userId', ParseUUIDPipe) userId: string,
  ): Promise<ResponseExternalProfileDto> {
    const profile = await this.companiesService.findProfileByUserId(userId);
    return new ResponseExternalProfileDto(profile);
  }

  @Post('ff-clients')
  @ApiOperation({ summary: 'Link a forwarder to a client company' })
  async createFFClient(@Body() dto: CreateFFClientDto): Promise<ResponseFFClientDto> {
    const client = await this.companiesService.createFFClient(dto);
    return new ResponseFFClientDto(client);
  }

  @Get(':forwarderCompanyId/clients')
  @ApiOperation({ summary: 'List clients of a forwarder' })
  async listFFClients(
    @Param('forwarderCompanyId', ParseUUIDPipe) forwarderCompanyId: string,
  ): Promise<ResponseFFClientDto[]> {
    const clients = await this.companiesService.findForwarderClients(forwarderCompanyId);
    return clients.map((c) => new ResponseFFClientDto(c));
  }

  @Delete('ff-clients/:id')
  @ApiOperation({ summary: 'Remove a forwarder-client relationship' })
  @HttpCode(HttpStatus.NO_CONTENT)
  async removeFFClient(@Param('id', ParseUUIDPipe) id: string): Promise<void> {
    await this.companiesService.deleteFFClient(id);
  }
}
