import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  ParseUUIDPipe,
  Post,
  Put,
  Query,
  UseGuards,
} from '@nestjs/common';
import {
  IsBoolean,
  IsEnum,
  IsNumber,
  IsOptional,
  IsString,
  IsUUID,
} from 'class-validator';
import {
  CustomerType,
  LocationType,
  PartnerRole,
  SupplierType,
} from '@prisma/client';
import { JwtAuthGuard } from '@modules/organization/auth/guards/jwt-auth.guard';
import { PermissionsGuard } from '@modules/organization/auth/guards/permissions.guard';
import { RequirePermissions } from '@common/decorators/permissions.decorator';
import { CurrentUser } from '@common/decorators/current-user.decorator';
import type { CurrentUserPayload } from '@common/decorators/current-user.decorator';
import { Auditable, Sensitive } from '@core/observability/audit/decorators/auditable.decorator';
import { NIL_ORG_ID } from '@common/constants/nil-uuid';
import { CustomerService } from './services/customer.service';
import { SupplierService } from './services/supplier.service';
import { PartnerService } from './services/partner.service';
import { LocationService } from './services/location.service';
import { CurrencyService } from './services/currency.service';

class CurrencyDto {
  @IsString() code!: string;
  @IsString() name!: string;
  @IsOptional() @IsString() symbol?: string;
  @IsOptional() @IsNumber() decimals?: number;
  @IsOptional() @IsBoolean() enabled?: boolean;
}

class UpdateCurrencyDto {
  @IsOptional() @IsString() name?: string;
  @IsOptional() @IsString() symbol?: string;
  @IsOptional() @IsNumber() decimals?: number;
  @IsOptional() @IsBoolean() enabled?: boolean;
}

class CustomerDto {
  @IsOptional() @IsString() code?: string;
  @IsString() name!: string;
  @IsOptional() @IsEnum(CustomerType) type?: CustomerType;
  @IsOptional() @IsString() industry?: string;
  @IsOptional() @IsString() countryCode?: string;
  @IsOptional() @IsString() taxId?: string;
  @IsOptional() @IsNumber() creditLimit?: number;
  @IsOptional() @IsString() currencyCode?: string;
  @IsOptional() @IsBoolean() enabled?: boolean;
}

class UpdateCustomerDto {
  @IsOptional() @IsString() name?: string;
  @IsOptional() @IsEnum(CustomerType) type?: CustomerType;
  @IsOptional() @IsString() industry?: string;
  @IsOptional() @IsString() countryCode?: string;
  @IsOptional() @IsString() taxId?: string;
  @IsOptional() @IsNumber() creditLimit?: number;
  @IsOptional() @IsString() currencyCode?: string;
  @IsOptional() @IsBoolean() enabled?: boolean;
}

class SupplierDto {
  @IsOptional() @IsString() code?: string;
  @IsString() name!: string;
  @IsOptional() @IsEnum(SupplierType) type?: SupplierType;
  @IsOptional() @IsString() countryCode?: string;
  @IsOptional() @IsString() currencyCode?: string;
  @IsOptional() @IsString() paymentTerms?: string;
  @IsOptional() @IsNumber() leadTimeDays?: number;
  @IsOptional() @IsBoolean() enabled?: boolean;
}

class UpdateSupplierDto {
  @IsOptional() @IsString() name?: string;
  @IsOptional() @IsEnum(SupplierType) type?: SupplierType;
  @IsOptional() @IsString() countryCode?: string;
  @IsOptional() @IsString() currencyCode?: string;
  @IsOptional() @IsString() paymentTerms?: string;
  @IsOptional() @IsNumber() leadTimeDays?: number;
  @IsOptional() @IsBoolean() enabled?: boolean;
}

class PartnerDto {
  @IsOptional() @IsString() code?: string;
  @IsString() name!: string;
  @IsEnum(PartnerRole) role!: PartnerRole;
  @IsOptional() @IsString() countryCode?: string;
  @IsOptional() @IsString() currencyCode?: string;
  @IsOptional() @IsBoolean() enabled?: boolean;
}

class UpdatePartnerDto {
  @IsOptional() @IsString() name?: string;
  @IsOptional() @IsEnum(PartnerRole) role?: PartnerRole;
  @IsOptional() @IsString() countryCode?: string;
  @IsOptional() @IsString() currencyCode?: string;
  @IsOptional() @IsBoolean() enabled?: boolean;
}

class LocationDto {
  @IsOptional() @IsString() code?: string;
  @IsString() name!: string;
  @IsEnum(LocationType) type!: LocationType;
  @IsOptional() @IsString() countryCode?: string;
  @IsOptional() @IsString() address?: string;
  @IsOptional() @IsUUID() parentLocationId?: string;
  @IsOptional() @IsUUID() customerId?: string;
  @IsOptional() @IsBoolean() enabled?: boolean;
}

class UpdateLocationDto {
  @IsOptional() @IsString() name?: string;
  @IsOptional() @IsEnum(LocationType) type?: LocationType;
  @IsOptional() @IsString() countryCode?: string;
  @IsOptional() @IsString() address?: string;
  @IsOptional() @IsUUID() parentLocationId?: string;
  @IsOptional() @IsUUID() customerId?: string;
  @IsOptional() @IsBoolean() enabled?: boolean;
}

@Controller('platform-master')
@UseGuards(JwtAuthGuard, PermissionsGuard)
export class MasterDataController {
  constructor(
    private readonly customer: CustomerService,
    private readonly supplier: SupplierService,
    private readonly partner: PartnerService,
    private readonly location: LocationService,
    private readonly currency: CurrencyService,
  ) {}

  // -------- Currencies (admin CRUD; GET/list 走 PlatformMasterController) --------
  @Post('currencies')
  @Auditable()
  @RequirePermissions('robot-manager:manage:customers')
  createCurrency(@Body() dto: CurrencyDto, @CurrentUser() user: CurrentUserPayload) {
    return this.currency.create(dto, user.userId, NIL_ORG_ID);
  }
  @Put('currencies/:code')
  @Auditable()
  @RequirePermissions('robot-manager:manage:customers')
  updateCurrency(@Param('code') code: string, @Body() dto: UpdateCurrencyDto) {
    return this.currency.update(code.toUpperCase(), dto);
  }
  @Delete('currencies/:code')
  @Auditable()
  @RequirePermissions('robot-manager:manage:customers')
  disableCurrency(@Param('code') code: string) {
    return this.currency.setEnabled(code.toUpperCase(), false);
  }
  @Post('currencies/:code/enable')
  @Auditable()
  @RequirePermissions('robot-manager:manage:customers')
  enableCurrency(@Param('code') code: string) {
    return this.currency.setEnabled(code.toUpperCase(), true);
  }

  // -------- Customers --------
  @Get('customers')
  @RequirePermissions('robot-manager:read')
  listCustomers(
    @Query('search') search?: string,
    @Query('type') type?: CustomerType,
    @Query('enabledOnly') enabledOnly?: string,
  ) {
    return this.customer.list({ search, type, enabledOnly: enabledOnly === 'true' });
  }
  @Get('customers/:id')
  @RequirePermissions('robot-manager:read')
  getCustomer(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.customer.findOne(id);
  }
  @Post('customers')
  @Auditable()
  @RequirePermissions('robot-manager:manage:customers')
  createCustomer(@Body() dto: CustomerDto, @CurrentUser() user: CurrentUserPayload) {
    return this.customer.create(dto, user.userId, NIL_ORG_ID);
  }
  @Put('customers/:id')
  @Auditable()
  @RequirePermissions('robot-manager:manage:customers')
  updateCustomer(@Param('id', new ParseUUIDPipe()) id: string, @Body() dto: UpdateCustomerDto) {
    return this.customer.update(id, dto);
  }
  @Delete('customers/:id')
  @Auditable()
  @Sensitive()
  @RequirePermissions('robot-manager:manage:customers')
  deleteCustomer(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.customer.softDelete(id);
  }
  @Post('customers/:id/restore')
  @Auditable()
  @RequirePermissions('robot-manager:manage:customers')
  restoreCustomer(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.customer.restore(id);
  }

  // -------- Suppliers --------
  @Get('suppliers')
  @RequirePermissions('robot-manager:read')
  listSuppliers(
    @Query('search') search?: string,
    @Query('type') type?: SupplierType,
    @Query('enabledOnly') enabledOnly?: string,
  ) {
    return this.supplier.list({ search, type, enabledOnly: enabledOnly === 'true' });
  }
  @Get('suppliers/:id')
  @RequirePermissions('robot-manager:read')
  getSupplier(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.supplier.findOne(id);
  }
  @Post('suppliers')
  @Auditable()
  @RequirePermissions('robot-manager:manage:suppliers')
  createSupplier(@Body() dto: SupplierDto, @CurrentUser() user: CurrentUserPayload) {
    return this.supplier.create(dto, user.userId, NIL_ORG_ID);
  }
  @Put('suppliers/:id')
  @Auditable()
  @RequirePermissions('robot-manager:manage:suppliers')
  updateSupplier(@Param('id', new ParseUUIDPipe()) id: string, @Body() dto: UpdateSupplierDto) {
    return this.supplier.update(id, dto);
  }
  @Delete('suppliers/:id')
  @Auditable()
  @Sensitive()
  @RequirePermissions('robot-manager:manage:suppliers')
  deleteSupplier(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.supplier.softDelete(id);
  }
  @Post('suppliers/:id/restore')
  @Auditable()
  @RequirePermissions('robot-manager:manage:suppliers')
  restoreSupplier(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.supplier.restore(id);
  }

  // -------- Partners --------
  @Get('partners')
  @RequirePermissions('robot-manager:read')
  listPartners(
    @Query('search') search?: string,
    @Query('role') role?: PartnerRole,
    @Query('enabledOnly') enabledOnly?: string,
  ) {
    return this.partner.list({ search, role, enabledOnly: enabledOnly === 'true' });
  }
  @Get('partners/:id')
  @RequirePermissions('robot-manager:read')
  getPartner(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.partner.findOne(id);
  }
  @Post('partners')
  @Auditable()
  @RequirePermissions('robot-manager:manage:partners')
  createPartner(@Body() dto: PartnerDto, @CurrentUser() user: CurrentUserPayload) {
    return this.partner.create(dto, user.userId, NIL_ORG_ID);
  }
  @Put('partners/:id')
  @Auditable()
  @RequirePermissions('robot-manager:manage:partners')
  updatePartner(@Param('id', new ParseUUIDPipe()) id: string, @Body() dto: UpdatePartnerDto) {
    return this.partner.update(id, dto);
  }
  @Delete('partners/:id')
  @Auditable()
  @Sensitive()
  @RequirePermissions('robot-manager:manage:partners')
  deletePartner(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.partner.softDelete(id);
  }
  @Post('partners/:id/restore')
  @Auditable()
  @RequirePermissions('robot-manager:manage:partners')
  restorePartner(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.partner.restore(id);
  }

  // -------- Locations --------
  @Get('locations')
  @RequirePermissions('robot-manager:read')
  listLocations(
    @Query('search') search?: string,
    @Query('type') type?: LocationType,
    @Query('customerId') customerId?: string,
    @Query('enabledOnly') enabledOnly?: string,
  ) {
    return this.location.list({ search, type, customerId, enabledOnly: enabledOnly === 'true' });
  }
  @Get('locations/:id')
  @RequirePermissions('robot-manager:read')
  getLocation(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.location.findOne(id);
  }
  @Post('locations')
  @Auditable()
  @RequirePermissions('robot-manager:manage:locations')
  createLocation(@Body() dto: LocationDto, @CurrentUser() user: CurrentUserPayload) {
    return this.location.create(dto, user.userId, NIL_ORG_ID);
  }
  @Put('locations/:id')
  @Auditable()
  @RequirePermissions('robot-manager:manage:locations')
  updateLocation(@Param('id', new ParseUUIDPipe()) id: string, @Body() dto: UpdateLocationDto) {
    return this.location.update(id, dto);
  }
  @Delete('locations/:id')
  @Auditable()
  @Sensitive()
  @RequirePermissions('robot-manager:manage:locations')
  deleteLocation(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.location.softDelete(id);
  }
  @Post('locations/:id/restore')
  @Auditable()
  @RequirePermissions('robot-manager:manage:locations')
  restoreLocation(@Param('id', new ParseUUIDPipe()) id: string) {
    return this.location.restore(id);
  }
}
