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 { FreightAdmin } from "../../common/booking-guards";
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 { CreateCompanyWithProfileDto } from "./dto/create-company-with-profile.dto";
import { AddCompanyProfilesDto } from "./dto/add-company-profiles.dto";
import { CreateCompanyProfileDto } from "./dto/create-company-profile.dto";
import { SetActiveModeDto } from "./dto/set-active-mode.dto";
import { SetOnboardingStepDto } from "./dto/set-onboarding-step.dto";
import { StartOnboardingDto } from "./dto/start-onboarding.dto";
import { DashboardQueryDto } from "./dto/dashboard-query.dto";
import {
  ResponseCompanyDto,
  ResponseCompanyProfileDto,
} from "./dto/response-company.dto";
import { BusinessLicenseFile } from "./entities/company-profile.entity";
import { ResponseExternalProfileDto } from "./dto/response-external-profile.dto";
import { CompanyInfoResponseDto } from "./dto/company-info-response.dto";
import { UpdateProfileDto } from "./dto/update-profile.dto";
import { ProfileResponseDto } from "./dto/profile-response.dto";
import { DashboardSummaryResponseDto } from "./dto/dashboard-summary-response.dto";
import { ListCompaniesQueryDto } from "./dto/list-companies-query.dto";
import { CompanyStatsResponseDto } from "./dto/company-stats-response.dto";
import { UpdateCompanyProfileStatusDto } from "./dto/update-company-profile-status.dto";
import { FetchETradeDto } from "./dto/fetch-etrade.dto";
import { ETradeResponseDto } from "./dto/etrade-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);
  }

  @Get("dashboard")
  @ApiOperation({
    summary:
      "Get portal dashboard KPIs (delivered, spend, freight volume) for the current user",
  })
  async getDashboard(
    @CurrentUser() user: CurrentIamUser,
    @Query() query: DashboardQueryDto,
  ): Promise<DashboardSummaryResponseDto> {
    return this.companiesService.getDashboardSummary(
      user.id,
      query.companyProfileId,
    );
  }

  @Post("fetch-etrade-info")
  @ApiOperation({ summary: "Fetch company info from eTrade by TIN" })
  async fetchETradeInfo(
    @Body() dto: FetchETradeDto,
  ): Promise<ETradeResponseDto> {
    const data = await this.companiesService.fetchETradeData(dto.tin);
    return new ETradeResponseDto(data);
  }

  @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("company-profiles")
  @ApiOperation({
    summary:
      "Add operational profile(s) (importer/exporter/forwarder) to the current user's company",
  })
  async addCompanyProfiles(
    @CurrentUser() user: CurrentIamUser,
    @Body() dto: AddCompanyProfilesDto,
  ): Promise<ResponseCompanyProfileDto[]> {
    const profiles = await this.companiesService.addCompanyProfilesForUser(
      user.id,
      dto.types,
    );
    return profiles.map((p) => new ResponseCompanyProfileDto(p));
  }

  @Post("onboarding/start")
  @ApiOperation({
    summary:
      "Begin onboarding: create a draft company + profile + role(s) so later steps can save incrementally",
  })
  async startOnboarding(
    @CurrentUser() user: CurrentIamUser,
    @Body() dto: StartOnboardingDto,
  ): Promise<CompanyInfoResponseDto> {
    const nameParts = (user.name?.en ?? "").split(" ");
    const { profile, company } = await this.companiesService.startOnboarding(
      {
        userId: user.id,
        firstName: nameParts[0] || "",
        lastName: nameParts.slice(-1)[0] || "",
        email: user.email ?? "",
        phone: user.phoneNumber ?? "",
      },
      dto.companyType,
      dto.roles,
      dto.nationality,
    );
    return new CompanyInfoResponseDto(profile, company);
  }

  @Post("company-profile")
  @ApiOperation({
    summary:
      "Create a single operational profile for the current user's company and make it the active mode",
  })
  async createCompanyProfile(
    @CurrentUser() user: CurrentIamUser,
    @Body() dto: CreateCompanyProfileDto,
  ): Promise<ResponseCompanyProfileDto> {
    const profile = await this.companiesService.createCompanyProfileForUser(
      user.id,
      dto.type,
      dto.businessLicense,
    );
    return new ResponseCompanyProfileDto(profile);
  }

  @Post("company-profiles/:profileId/license")
  @UseInterceptors(AnyFilesInterceptor())
  @ApiConsumes("multipart/form-data")
  @ApiOperation({
    summary:
      "Upload business-license document(s) for one of the current user's company profiles",
  })
  async uploadProfileLicense(
    @CurrentUser() user: CurrentIamUser,
    @Param("profileId", ParseUUIDPipe) profileId: string,
    @UploadedFiles() files: Array<Express.Multer.File>,
  ): Promise<BusinessLicenseFile[]> {
    return this.companiesService.uploadProfileLicenseFiles(
      user.id,
      profileId,
      files,
    );
  }

  @Get("company-profiles/:profileId/license")
  @ApiOperation({
    summary: "List business-license documents for a company profile",
  })
  async listProfileLicense(
    @CurrentUser() user: CurrentIamUser,
    @Param("profileId", ParseUUIDPipe) profileId: string,
  ): Promise<BusinessLicenseFile[]> {
    return this.companiesService.listProfileLicenseFiles(user.id, profileId);
  }

  @Patch("active-mode")
  @ApiOperation({
    summary: "Switch the current user's active operational mode (importer/exporter)",
  })
  async setActiveMode(
    @CurrentUser() user: CurrentIamUser,
    @Body() dto: SetActiveModeDto,
  ): Promise<CompanyInfoResponseDto> {
    const { profile, company } = await this.companiesService.setActiveMode(
      user.id,
      dto.type,
    );
    return new CompanyInfoResponseDto(profile, company);
  }

  @Patch("onboarding-step")
  @ApiOperation({ summary: "Persist the user's current onboarding wizard step" })
  @HttpCode(HttpStatus.NO_CONTENT)
  async setOnboardingStep(
    @CurrentUser() user: CurrentIamUser,
    @Body() dto: SetOnboardingStepDto,
  ): Promise<void> {
    await this.companiesService.setOnboardingStep(user.id, dto.step);
  }

  @Post("onboarding/complete")
  @ApiOperation({ summary: "Mark the current user's onboarding as complete" })
  async completeOnboarding(
    @CurrentUser() user: CurrentIamUser,
  ): Promise<CompanyInfoResponseDto> {
    const { profile, company } =
      await this.companiesService.markOnboardingComplete(user.id);
    return new CompanyInfoResponseDto(profile, company);
  }

  // Used by portal
  @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);
  }

  // Used by backoffice
  @Post()
  @FreightAdmin()
  @ApiOperation({
    summary:
      "Create a new company (customer, freight_forwarder, dj_freight_forwarder, transporter)",
  })
  async create(@Body() dto: CreateCompanyDto): Promise<ResponseCompanyDto> {
    const company = await this.companiesService.createCompany(dto);
    return new ResponseCompanyDto(company);
  }

  @Get("stats")
  @ApiOperation({ summary: "Company counts by status (KPI strip)" })
  async getStats(): Promise<CompanyStatsResponseDto> {
    return this.companiesService.getCompanyStats();
  }

  @Get()
  @ApiOperation({ summary: "List companies (paginated, filterable)" })
  async findAll(
    @Query() query: ListCompaniesQueryDto,
  ): Promise<{ items: ResponseCompanyDto[]; total: number }> {
    const { items, total } = await this.companiesService.listCompanies(query);
    return { items: items.map((c) => new ResponseCompanyDto(c)), total };
  }

  @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")
  @FreightAdmin()
  @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")
  @FreightAdmin()
  @ApiOperation({ summary: "Soft-delete a company" })
  @HttpCode(HttpStatus.NO_CONTENT)
  async remove(@Param("id", ParseUUIDPipe) id: string): Promise<void> {
    await this.companiesService.deleteCompany(id);
  }

  @Get(":companyId/documents")
  @ApiOperation({ summary: "List documents uploaded for a company" })
  async listDocuments(
    @Param("companyId", ParseUUIDPipe) companyId: string,
  ) {
    const files = await this.filesService.findByResource(companyId, "companies");
    return files.map((f) => ({
      id: f.id,
      name: f.name,
      code: f.code,
      mimeType: f.mimeType,
      size: f.size,
      uploadedAt: f.createdAt,
      url: f.url,
    }));
  }

  @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);
  }

  @Patch("company-profiles/:profileId/status")
  @FreightAdmin()
  @ApiOperation({ summary: "Update a company profile's approval status" })
  async updateCompanyProfileStatus(
    @Param("profileId", ParseUUIDPipe) profileId: string,
    @Body() dto: UpdateCompanyProfileStatusDto,
  ): Promise<ResponseCompanyProfileDto> {
    const profile = await this.companiesService.setCompanyProfileStatus(
      profileId,
      dto.status,
    );
    return new ResponseCompanyProfileDto(profile);
  }

  @Post(":companyId/profiles")
  @FreightAdmin()
  @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);
  }
}
