#!/bin/bash
set -euo pipefail

# POST-CHECK: Backend — Entity, Service & Controller Checks
# V1-V2, C8, C12, C14, C28-C31, C54, C62: Entity validation, API contracts, pagination, code generation, tenant exceptions

FAIL=false

# POST-CHECK V1: Controllers with POST/PUT must have corresponding Validators (BLOCKING)
CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
if [ -n "$CTRL_FILES" ]; then
  for f in $CTRL_FILES; do
    HAS_WRITE=$(grep -cE "\[Http(Post|Put)\]" "$f" || true)
    if [ "$HAS_WRITE" -gt 0 ]; then
      DTOS=$(grep -oE '(Create|Update)[A-Za-z0-9_]+Dto' "$f" | sort -u || true)
      for DTO in $DTOS; do
        VALIDATOR_NAME=$(echo "$DTO" | sed 's/Dto$/Validator/')
        VALIDATOR_FILE=$(find src/ -path "*/Validators/*" -name "${VALIDATOR_NAME}.cs" 2>/dev/null)
        if [ -z "$VALIDATOR_FILE" ]; then
          echo "BLOCKING: Controller $f uses $DTO but no ${VALIDATOR_NAME}.cs found"
          echo "Fix: Create Validator with FluentValidation rules from business rules"
          FAIL=true
        fi
      done
    fi
  done
fi

# POST-CHECK V2: Validators must be registered in DI (WARNING)
VALIDATOR_FILES=$(find src/ -path "*/Validators/*" -name "*Validator.cs" 2>/dev/null)
if [ -n "$VALIDATOR_FILES" ]; then
  DI_FILE=$(find src/ -name "DependencyInjection.cs" -o -name "ServiceCollectionExtensions.cs" 2>/dev/null | head -1)
  if [ -n "$DI_FILE" ]; then
    for f in $VALIDATOR_FILES; do
      VALIDATOR_NAME=$(basename "$f" .cs)
      if ! grep -q "$VALIDATOR_NAME" "$DI_FILE"; then
        echo "WARNING: Validator $VALIDATOR_NAME not registered in DI: $DI_FILE"
      fi
    done
  fi
fi

# POST-CHECK C8: Backend APIs must support search parameter for EntityLookup (BLOCKING)
CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
if [ -n "$CTRL_FILES" ]; then
  for f in $CTRL_FILES; do
    if grep -q "\[HttpGet\]" "$f" && grep -q "GetAll" "$f"; then
      if ! grep -q "search" "$f"; then
        echo "BLOCKING: Controller missing search parameter on GetAll: $f"
        echo "GetAll endpoints must accept ?search= to enable EntityLookup on frontend"
        echo "Fix: Add [FromQuery] string? search parameter to GetAll action"
        FAIL=true
      fi
    fi
  done
fi

WEB_DIR=$(find . -name "vitest.config.ts" -o -name "vite.config.ts" 2>/dev/null | head -1 | xargs dirname 2>/dev/null)
if [ -n "$WEB_DIR" ]; then
  LOOKUP_FILES=$(grep -rl "EntityLookup" "$WEB_DIR/src/pages/" "$WEB_DIR/src/components/" 2>/dev/null | grep -v node_modules | grep -v "\.test\." || true)
  if [ -n "$LOOKUP_FILES" ]; then
    for f in $LOOKUP_FILES; do
      ENDPOINTS=$(grep -oE "apiEndpoint=['\"][^'\"]+['\"]" "$f" 2>/dev/null | sed "s/apiEndpoint=//;s/['\"]//g" || true)
      for ep in $ENDPOINTS; do
        ENTITY=$(echo "$ep" | sed 's|.*/||' | sed 's/.*/\u&/')
        CTRL=$(find src/ -path "*/Controllers/*${ENTITY}*Controller.cs" 2>/dev/null | head -1)
        if [ -n "$CTRL" ] && ! grep -q "search" "$CTRL"; then
          echo "BLOCKING: EntityLookup in $f calls $ep, but controller $CTRL does not support ?search="
          echo "Fix: Add [FromQuery] string? search parameter to GetAll in $CTRL"
          FAIL=true
        fi
      done
    done
  fi
fi

# POST-CHECK C12: GetAll methods must return PaginatedResult<T>
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
if [ -n "$SERVICE_FILES" ]; then
  BAD_RETURNS=$(grep -nE 'Task<\s*(List|IEnumerable|IList|ICollection|IReadOnlyList|IReadOnlyCollection)<.*GetAll' $SERVICE_FILES 2>/dev/null || true)
  if [ -n "$BAD_RETURNS" ]; then
    echo "WARNING: GetAll methods must return PaginatedResult<T>, not List/IEnumerable"
    echo "$BAD_RETURNS"
    echo "Fix: Change return type to Task<PaginatedResult<{Entity}ResponseDto>>"
  fi
fi

# POST-CHECK C14: Entities must implement IAuditableEntity + Validators must have Create/Update pairs
ENTITY_FILES=$(find src/ -path "*/Domain/Entities/*" -name "*.cs" 2>/dev/null)
if [ -n "$ENTITY_FILES" ]; then
  for f in $ENTITY_FILES; do
    if grep -q "ITenantEntity" "$f" && ! grep -q "IAuditableEntity" "$f"; then
      echo "WARNING: Entity implements ITenantEntity but NOT IAuditableEntity: $f"
      echo "Pattern: public class Entity : BaseEntity, ITenantEntity, IAuditableEntity"
    fi
  done
fi

CREATE_VALIDATORS=$(find src/ -path "*/Validators/*" -name "Create*Validator.cs" 2>/dev/null)
if [ -n "$CREATE_VALIDATORS" ]; then
  for f in $CREATE_VALIDATORS; do
    VALIDATOR_DIR=$(dirname "$f")
    ENTITY_NAME=$(basename "$f" | sed 's/^Create\(.*\)Validator\.cs$/\1/')
    if [ ! -f "$VALIDATOR_DIR/Update${ENTITY_NAME}Validator.cs" ]; then
      echo "WARNING: Create${ENTITY_NAME}Validator exists but Update${ENTITY_NAME}Validator is missing"
      echo "  Found: $f"
      echo "  Expected: $VALIDATOR_DIR/Update${ENTITY_NAME}Validator.cs"
    fi
  done
fi

# POST-CHECK C28: Pagination type must be PaginatedResult<T> — no aliases (WARNING)
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
ALL_FILES="$SERVICE_FILES $CTRL_FILES"
if [ -n "$(echo $ALL_FILES | tr -d ' ')" ]; then
  BAD_NAMES=$(grep -nE 'PagedResult<|PaginatedResultDto<|PaginatedResponse<|PageResultDto<' $ALL_FILES 2>/dev/null || true)
  if [ -n "$BAD_NAMES" ]; then
    echo "WARNING: Pagination type must be PaginatedResult<T> — found non-canonical names"
    echo "$BAD_NAMES"
    echo "FORBIDDEN type names: PagedResult, PaginatedResultDto, PaginatedResponse, PageResultDto"
    echo "Fix: Use PaginatedResult<T> from SmartStack.Application.Common.Models everywhere"
  fi
fi

# POST-CHECK C29: Code generation — ICodeGenerator must be registered for auto-generated entities (BLOCKING)
FEATURE_FILES=$(find docs/ -name "feature.json" 2>/dev/null)
DI_FILE=$(find src/ -name "DependencyInjection.cs" -path "*/Infrastructure/*" 2>/dev/null | head -1)
if [ -n "$FEATURE_FILES" ] && [ -n "$DI_FILE" ]; then
  for FEATURE in $FEATURE_FILES; do
    ENTITIES_WITH_CODE=$(python3 -c "
import json, sys
try:
  with open('$FEATURE') as f:
    data = json.load(f)
  for e in data.get('analysis', {}).get('entities', []):
    cp = e.get('codePattern', {})
    if cp.get('strategy', 'manual') != 'manual':
      print(e['name'])
except: pass
" 2>/dev/null || true)
    for ENTITY in $ENTITIES_WITH_CODE; do
      if ! grep -q "ICodeGenerator<$ENTITY>" "$DI_FILE" 2>/dev/null; then
        echo "BLOCKING: Entity $ENTITY has auto-generated code pattern but ICodeGenerator<$ENTITY> is not registered in DI"
        echo "Fix: Add CodeGenerator<$ENTITY> registration in DependencyInjection.cs — see references/code-generation.md"
        FAIL=true
      fi
    done
  done
fi

# POST-CHECK C30: Code regex must support hyphens (BLOCKING)
VALIDATOR_FILES=$(find src/ -path "*/Validators/*" -name "*Validator.cs" 2>/dev/null)
if [ -n "$VALIDATOR_FILES" ]; then
  OLD_REGEX=$(grep -rn '\^\\[a-z0-9_\\]+\$' $VALIDATOR_FILES 2>/dev/null | grep -v '\-' || true)
  if [ -n "$OLD_REGEX" ]; then
    echo "BLOCKING: Code validator uses old regex without hyphen support"
    echo "$OLD_REGEX"
    echo "Fix: Update regex to ^[a-z0-9_-]+$ to support auto-generated codes with hyphens"
    FAIL=true
  fi
fi

# POST-CHECK C31: CreateDto must NOT have Code field when service uses ICodeGenerator (WARNING)
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
if [ -n "$SERVICE_FILES" ]; then
  for f in $SERVICE_FILES; do
    if grep -q "ICodeGenerator" "$f"; then
      ENTITY=$(basename "$f" | sed 's/Service\.cs$//')
      DTO_FILE=$(find src/ -path "*/DTOs/*" -name "Create${ENTITY}Dto.cs" 2>/dev/null | head -1)
      if [ -n "$DTO_FILE" ] && grep -q "public string Code" "$DTO_FILE"; then
        echo "WARNING: Create${ENTITY}Dto has Code field but service uses ICodeGenerator (code is auto-generated)"
        echo "Fix: Remove Code from Create${ENTITY}Dto — it is auto-generated by ICodeGenerator<${ENTITY}>"
      fi
    fi
  done
fi

# POST-CHECK C54: No helper method calls inside .Select() on IQueryable (BLOCKING)
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
if [ -n "$SERVICE_FILES" ]; then
  BAD_SELECT=$(grep -nE '\.Select\([[:space:]]*[a-z]+[[:space:]]*=>[[:space:]]*[A-Z][A-Za-z0-9_]+\(' $SERVICE_FILES 2>/dev/null | grep -v '=>\s*new\s' || true)
  if [ -n "$BAD_SELECT" ]; then
    echo "BLOCKING: Helper method call inside .Select() on IQueryable — EF Core cannot translate to SQL"
    echo "$BAD_SELECT"
    echo "Fix: Use inline DTO construction: .Select(x => new ResponseDto(x.Id, x.Name, x.FK.Code))"
    echo "  Helper methods (MapToDto, ToDto) are only safe AFTER materialization (ToListAsync, FirstAsync)"
    FAIL=true
  fi
fi

# POST-CHECK C62: Services must use TenantContextRequiredException, NOT InvalidOperationException for tenant (WARNING)
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
if [ -n "$SERVICE_FILES" ]; then
  for f in $SERVICE_FILES; do
    BAD_TENANT=$(grep -nE 'throw new InvalidOperationException.*[Tt]enant' "$f" 2>/dev/null || true)
    if [ -n "$BAD_TENANT" ]; then
      echo "WARNING: Service uses InvalidOperationException for tenant check (returns 500 instead of 400): $f"
      echo "  $BAD_TENANT"
      echo "  Fix: Use 'throw new TenantContextRequiredException()' instead"
      echo "  TenantContextRequiredException returns 400 via GlobalExceptionHandlerMiddleware"
    fi
  done
fi

if [ "$FAIL" = true ]; then
  exit 1
fi
