import { Body, Controller, Get, Param, Patch, Query } from '@nestjs/common';
import { ApiBody, ApiOperation, ApiParam, ApiQuery, ApiResponse, ApiTags } from '@nestjs/swagger';
import { UserRole } from '@prisma/client';
import { RequireRole } from '../auth/require-role.decorator';
import { CurrentUser } from '../common/current-user.decorator';
import { RequestUser } from '../common/request-user';
import { ApiProtectedEndpoint, ApiValidationError, ESTATE_ID_EXAMPLE } from '../common/swagger-docs';
import { UpdatePlanFeatureSettingsDto, UpdateRoleFeatureSettingsDto } from './dto/feature-access.dto';
import { FeatureAccessService } from './feature-access.service';
import { FeatureKey } from './feature-catalog';
import { RequireFeature } from './require-feature.decorator';

const ALL_ROLES = [
  UserRole.SUPER_ADMIN,
  UserRole.SALES_ADMIN,
  UserRole.ESTATE_ADMIN,
  UserRole.SECURITY_SUPERVISOR,
  UserRole.GUARD,
  UserRole.RESIDENT
];

@ApiTags('Feature Access')
@ApiProtectedEndpoint()
@Controller({ path: 'features', version: '1' })
export class FeatureAccessController {
  constructor(private readonly featureAccess: FeatureAccessService) {}

  @Get('catalog')
  @RequireRole(...ALL_ROLES)
  @ApiOperation({
    summary: 'List feature catalog',
    description: 'Returns the stable feature keys, labels, categories, and default roles used by WebApp and MobileApp permission screens.'
  })
  @ApiResponse({
    status: 200,
    description: 'Feature catalog returned.',
    schema: {
      example: [
        {
          key: FeatureKey.VISITOR_PASSES_CREATE,
          label: 'Create visitor passes',
          category: 'Visitors',
          defaultRoles: ['SUPER_ADMIN', 'ESTATE_ADMIN', 'RESIDENT'],
          estateConfigurable: true
        }
      ]
    }
  })
  listCatalog() {
    return this.featureAccess.listCatalog();
  }

  @Get('me')
  @RequireRole(...ALL_ROLES)
  @ApiOperation({
    summary: 'List current user effective features',
    description: 'Returns the current user role features after applying global defaults, global overrides, and estate overrides.'
  })
  @ApiResponse({
    status: 200,
    description: 'Effective feature settings returned.',
    schema: {
      example: [
        {
          key: FeatureKey.CHECKIN_SCAN,
          role: 'GUARD',
          estateId: ESTATE_ID_EXAMPLE,
          defaultEnabled: true,
          globalEnabled: true,
          estateEnabled: null,
          effectiveEnabled: true,
          source: 'DEFAULT'
        }
      ]
    }
  })
  me(@CurrentUser() user: RequestUser) {
    return this.featureAccess.getMyFeatures(user);
  }

  @Get('role-settings')
  @RequireRole(UserRole.SUPER_ADMIN, UserRole.ESTATE_ADMIN)
  @RequireFeature(FeatureKey.FEATURE_SETTINGS_MANAGE)
  @ApiOperation({
    summary: 'Inspect role feature settings',
    description:
      'SUPER_ADMIN can inspect any global or estate role settings. ESTATE_ADMIN can inspect only resident or guard settings for their own estate.'
  })
  @ApiQuery({ name: 'role', enum: UserRole, example: UserRole.RESIDENT })
  @ApiQuery({ name: 'estateId', required: false, example: ESTATE_ID_EXAMPLE })
  @ApiResponse({ status: 200, description: 'Role feature settings returned.' })
  getRoleSettings(
    @Query('role') role: UserRole,
    @Query('estateId') estateId: string | undefined,
    @CurrentUser() user: RequestUser
  ) {
    return this.featureAccess.getManageableRoleSettings(role, estateId, user);
  }

  @Patch('role-settings/:role')
  @RequireRole(UserRole.SUPER_ADMIN, UserRole.ESTATE_ADMIN)
  @RequireFeature(FeatureKey.FEATURE_SETTINGS_MANAGE)
  @ApiOperation({
    summary: 'Update role feature settings',
    description:
      'SUPER_ADMIN can update global settings for any role or estate overrides when estateId is supplied. ESTATE_ADMIN can update only RESIDENT and GUARD settings for their own estate.'
  })
  @ApiParam({ name: 'role', enum: UserRole, example: UserRole.GUARD })
  @ApiBody({
    type: UpdateRoleFeatureSettingsDto,
    examples: {
      disableGuardManualCheckin: {
        summary: 'Disable manual check-in for guards in one estate',
        value: {
          estateId: ESTATE_ID_EXAMPLE,
          settings: [{ feature: FeatureKey.CHECKIN_MANUAL, enabled: false }]
        }
      },
      enableSalesAdminPipeline: {
        summary: 'Enable sales admin signup review globally',
        value: {
          settings: [
            { feature: FeatureKey.ESTATE_SIGNUPS_VIEW, enabled: true },
            { feature: FeatureKey.ESTATE_SIGNUPS_REVIEW, enabled: true }
          ]
        }
      }
    }
  })
  @ApiResponse({ status: 200, description: 'Role feature settings updated.' })
  @ApiValidationError()
  updateRoleSettings(
    @Param('role') role: UserRole,
    @Body() dto: UpdateRoleFeatureSettingsDto,
    @CurrentUser() user: RequestUser
  ) {
    return this.featureAccess.updateRoleSettings(role, dto, user);
  }

  @Get('plan-settings/:code')
  @RequireRole(UserRole.SUPER_ADMIN)
  @RequireFeature(FeatureKey.FEATURE_SETTINGS_MANAGE)
  @ApiOperation({
    summary: 'Inspect plan feature settings',
    description: 'SUPER_ADMIN view of every feature and whether it is enabled for a subscription plan.'
  })
  @ApiParam({ name: 'code', example: 'SECURE' })
  @ApiResponse({ status: 200, description: 'Plan feature settings returned.' })
  getPlanSettings(@Param('code') code: string) {
    return this.featureAccess.getPlanSettings(code);
  }

  @Patch('plan-settings/:code')
  @RequireRole(UserRole.SUPER_ADMIN)
  @RequireFeature(FeatureKey.FEATURE_SETTINGS_MANAGE)
  @ApiOperation({
    summary: 'Update plan feature settings',
    description:
      'SUPER_ADMIN can activate or deactivate any feature for a subscription plan. Enabled features become available to plan-gated estate roles.'
  })
  @ApiParam({ name: 'code', example: 'SECURE' })
  @ApiBody({
    type: UpdatePlanFeatureSettingsDto,
    examples: {
      enableLuxuryRiskScoring: {
        summary: 'Enable visitor risk scoring',
        value: { settings: [{ feature: FeatureKey.VISITOR_RISK_SCORING, enabled: true }] }
      },
      disableStarterExports: {
        summary: 'Disable exports',
        value: { settings: [{ feature: FeatureKey.EXPORT_REPORTS, enabled: false }] }
      }
    }
  })
  @ApiResponse({ status: 200, description: 'Plan feature settings updated.' })
  @ApiValidationError()
  updatePlanSettings(
    @Param('code') code: string,
    @Body() dto: UpdatePlanFeatureSettingsDto,
    @CurrentUser() user: RequestUser
  ) {
    return this.featureAccess.updatePlanSettings(code, dto, user);
  }
}
