#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
用户管理系统 - 代码结构验证脚本
验证所有模块、接口、服务的完整性
"""

import os
import sys
from pathlib import Path
from typing import List, Dict, Tuple
import json

# 颜色输出
class Colors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKCYAN = '\033[96m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

# 项目根目录
PROJECT_ROOT = Path(__file__).parent.absolute()

# 预期的文件结构
EXPECTED_STRUCTURE = {
    "cmd/server/main.go": "主程序入口",
    "go.mod": "Go模块依赖",
    "Makefile": "构建脚本",
    
    # Domain层
    "internal/domain/user.go": "用户实体",
    "internal/domain/role.go": "角色实体",
    "internal/domain/permission.go": "权限实体",
    "internal/domain/device.go": "设备实体",
    "internal/domain/user_role.go": "用户角色关联",
    "internal/domain/role_permission.go": "角色权限关联",
    "internal/domain/login_log.go": "登录日志",
    "internal/domain/operation_log.go": "操作日志",
    
    # Repository层
    "internal/repository/user.go": "用户数据访问",
    "internal/repository/role.go": "角色数据访问",
    "internal/repository/permission.go": "权限数据访问",
    "internal/repository/device.go": "设备数据访问",
    "internal/repository/user_role.go": "用户角色关联",
    "internal/repository/role_permission.go": "角色权限关联",
    
    # Service层
    "internal/service/auth.go": "认证服务",
    "internal/service/user.go": "用户服务",
    "internal/service/role.go": "角色服务",
    "internal/service/permission.go": "权限服务",
    "internal/service/device.go": "设备服务",
    
    # Handler层
    "internal/api/handler/auth.go": "认证处理器",
    "internal/api/handler/user.go": "用户处理器",
    "internal/api/handler/role.go": "角色处理器",
    "internal/api/handler/permission.go": "权限处理器",
    "internal/api/handler/device.go": "设备处理器",
    
    # Middleware层
    "internal/api/middleware/auth.go": "认证中间件",
    "internal/api/middleware/ratelimit.go": "限流中间件",
    "internal/api/middleware/cors.go": "CORS中间件",
    "internal/api/middleware/error.go": "错误处理中间件",
    "internal/api/middleware/logger.go": "日志中间件",
    
    # 路由
    "internal/api/router/router.go": "路由配置",
    
    # 缓存
    "internal/cache/cache_manager.go": "缓存管理器",
    "internal/cache/l1.go": "L1本地缓存",
    "internal/cache/l2.go": "L2 Redis缓存",
    
    # 监控
    "internal/monitoring/metrics.go": "Prometheus指标",
    "internal/monitoring/health.go": "健康检查",
    "internal/monitoring/middleware.go": "监控中间件",
    
    # 认证
    "internal/auth/jwt.go": "JWT管理",
    "internal/auth/oauth.go": "OAuth",
    "internal/auth/password.go": "密码加密",
    
    # 安全
    "internal/security/ratelimit.go": "限流",
    "internal/security/validator.go": "参数验证",
    "internal/security/encryption.go": "加密工具",
    
    # 数据库
    "internal/database/db.go": "数据库初始化",
    
    # 配置
    "internal/config/config.go": "配置管理",
    
    # 响应
    "internal/response/response.go": "响应封装",
    
    # 错误
    "pkg/errors/errors.go": "错误定义",
    "pkg/response/response.go": "响应定义",
}

# 预期的API接口
EXPECTED_API_ENDPOINTS = {
    "认证接口": [
        "POST /api/v1/auth/register",
        "POST /api/v1/auth/login",
        "POST /api/v1/auth/refresh",
        "POST /api/v1/auth/logout",
        "POST /api/v1/auth/login/code",
    ],
    "用户接口": [
        "GET /api/v1/users",
        "GET /api/v1/users/me",
        "GET /api/v1/users/:id",
        "POST /api/v1/users",
        "PUT /api/v1/users/:id",
        "DELETE /api/v1/users/:id",
        "PUT /api/v1/users/:id/password",
        "PUT /api/v1/users/:id/status",
        "GET /api/v1/users/:id/roles",
        "PUT /api/v1/users/:id/roles",
    ],
    "角色接口": [
        "GET /api/v1/roles",
        "GET /api/v1/roles/:id",
        "POST /api/v1/roles",
        "PUT /api/v1/roles/:id",
        "DELETE /api/v1/roles/:id",
        "PUT /api/v1/roles/:id/status",
        "GET /api/v1/roles/:id/permissions",
        "PUT /api/v1/roles/:id/permissions",
    ],
    "权限接口": [
        "GET /api/v1/permissions",
        "GET /api/v1/permissions/tree",
        "GET /api/v1/permissions/:id",
        "POST /api/v1/permissions",
        "PUT /api/v1/permissions/:id",
        "DELETE /api/v1/permissions/:id",
        "PUT /api/v1/permissions/:id/status",
    ],
    "设备接口": [
        "GET /api/v1/devices",
        "GET /api/v1/devices/:id",
        "POST /api/v1/devices",
        "PUT /api/v1/devices/:id",
        "DELETE /api/v1/devices/:id",
        "PUT /api/v1/devices/:id/status",
        "GET /api/v1/devices/users/:id",
    ],
}

def print_success(msg: str):
    print(f"{Colors.OKGREEN}✓{Colors.ENDC} {msg}")

def print_error(msg: str):
    print(f"{Colors.FAIL}✗{Colors.ENDC} {msg}")

def print_warning(msg: str):
    print(f"{Colors.WARNING}⚠{Colors.ENDC} {msg}")

def print_info(msg: str):
    print(f"{Colors.OKBLUE}ℹ{Colors.ENDC} {msg}")

def verify_file_structure() -> Tuple[int, int, List[str]]:
    """验证文件结构"""
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}1. 文件结构验证{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    total = len(EXPECTED_STRUCTURE)
    exists = 0
    missing_files = []
    
    for file_path, description in EXPECTED_STRUCTURE.items():
        full_path = PROJECT_ROOT / file_path
        if full_path.exists():
            exists += 1
            size = full_path.stat().st_size
            print_success(f"{file_path:<50} ({size} bytes) - {description}")
        else:
            missing_files.append(file_path)
            print_error(f"{file_path:<50} - {description}")
    
    print(f"\n{Colors.OKCYAN}文件结构完成度: {exists}/{total} ({exists/total*100:.1f}%){Colors.ENDC}")
    
    return total, exists, missing_files

def verify_service_methods() -> Dict[str, List[str]]:
    """验证Service层方法"""
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}2. Service层方法验证{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    # Service文件及其预期方法
    service_methods = {
        "auth.go": [
            "Register",
            "Login",
            "LoginByCode",
            "SocialLogin",
            "RefreshToken",
            "Logout",
            "GetUserInfo",
            "SendVerificationCode",
        ],
        "user.go": [
            "GetUser",
            "GetUserByID",
            "ListUsers",
            "CreateUser",
            "UpdateUser",
            "DeleteUser",
            "UpdateUserStatus",
            "UpdatePassword",
            "GetUserRoles",
            "AssignRoles",
        ],
        "role.go": [
            "GetRole",
            "ListRoles",
            "CreateRole",
            "UpdateRole",
            "DeleteRole",
            "UpdateRoleStatus",
            "GetRolePermissions",
            "AssignPermissions",
        ],
        "permission.go": [
            "GetPermission",
            "ListPermissions",
            "GetPermissionTree",
            "CreatePermission",
            "UpdatePermission",
            "DeletePermission",
            "UpdatePermissionStatus",
            "Search",
        ],
        "device.go": [
            "GetDevice",
            "ListDevices",
            "CreateDevice",
            "UpdateDevice",
            "DeleteDevice",
            "UpdateDeviceStatus",
            "GetUserDevices",
        ],
    }
    
    results = {}
    
    for service_file, expected_methods in service_methods.items():
        print(f"\n{Colors.OKCYAN}📁 internal/service/{service_file}{Colors.ENDC}")
        
        file_path = PROJECT_ROOT / "internal/service" / service_file
        if not file_path.exists():
            print_error(f"文件不存在")
            results[service_file] = {"exists": False, "methods": []}
            continue
        
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        found_methods = []
        missing_methods = []
        
        for method in expected_methods:
            if f"func.*{method}" in content:
                found_methods.append(method)
                print_success(f"  ✓ {method}")
            else:
                missing_methods.append(method)
                print_error(f"  ✗ {method}")
        
        print(f"  {Colors.OKCYAN}完成度: {len(found_methods)}/{len(expected_methods)}{Colors.ENDC}")
        
        results[service_file] = {
            "exists": True,
            "found": found_methods,
            "missing": missing_methods,
            "total": len(expected_methods),
        }
    
    return results

def verify_handler_methods() -> Dict[str, List[str]]:
    """验证Handler层方法"""
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}3. Handler层方法验证{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    handler_methods = {
        "auth.go": [
            "Register",
            "Login",
            "LoginByCode",
            "SocialLogin",
            "RefreshToken",
            "Logout",
            "SendVerificationCode",
        ],
        "user.go": [
            "GetUser",
            "GetCurrentUser",
            "ListUsers",
            "CreateUser",
            "UpdateUser",
            "DeleteUser",
            "UpdateUserStatus",
            "UpdatePassword",
            "GetUserRoles",
            "AssignRoles",
        ],
        "role.go": [
            "CreateRole",
            "ListRoles",
            "GetRole",
            "UpdateRole",
            "DeleteRole",
            "UpdateRoleStatus",
            "GetRolePermissions",
            "AssignPermissions",
        ],
        "permission.go": [
            "CreatePermission",
            "ListPermissions",
            "GetPermissionTree",
            "GetPermission",
            "UpdatePermission",
            "DeletePermission",
            "UpdatePermissionStatus",
        ],
        "device.go": [
            "GetMyDevices",
            "CreateDevice",
            "GetDevice",
            "UpdateDevice",
            "DeleteDevice",
            "UpdateDeviceStatus",
            "GetUserDevices",
        ],
    }
    
    results = {}
    
    for handler_file, expected_methods in handler_methods.items():
        print(f"\n{Colors.OKCYAN}📁 internal/api/handler/{handler_file}{Colors.ENDC}")
        
        file_path = PROJECT_ROOT / "internal/api/handler" / handler_file
        if not file_path.exists():
            print_error(f"文件不存在")
            results[handler_file] = {"exists": False, "methods": []}
            continue
        
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        found_methods = []
        missing_methods = []
        
        for method in expected_methods:
            if f"func.*{method}" in content:
                found_methods.append(method)
                print_success(f"  ✓ {method}")
            else:
                missing_methods.append(method)
                print_error(f"  ✗ {method}")
        
        print(f"  {Colors.OKCYAN}完成度: {len(found_methods)}/{len(expected_methods)}{Colors.ENDC}")
        
        results[handler_file] = {
            "exists": True,
            "found": found_methods,
            "missing": missing_methods,
            "total": len(expected_methods),
        }
    
    return results

def verify_middleware() -> None:
    """验证中间件"""
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}4. 中间件验证{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    middlewares = [
        ("auth.go", "认证中间件"),
        ("ratelimit.go", "限流中间件"),
        ("cors.go", "CORS中间件"),
        ("logger.go", "日志中间件"),
        ("error.go", "错误处理中间件"),
    ]
    
    middleware_dir = PROJECT_ROOT / "internal/api/middleware"
    
    for middleware_file, description in middlewares:
        file_path = middleware_dir / middleware_file
        if file_path.exists():
            print_success(f"{middleware_file:<20} - {description}")
        else:
            print_error(f"{middleware_file:<20} - {description}")

def verify_cache() -> None:
    """验证缓存"""
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}5. 缓存模块验证{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    cache_files = [
        ("cache_manager.go", "缓存管理器 - L1+L2多级缓存"),
        ("l1.go", "L1本地缓存实现"),
        ("l2.go", "L2 Redis缓存实现"),
    ]
    
    cache_dir = PROJECT_ROOT / "internal/cache"
    
    for cache_file, description in cache_files:
        file_path = cache_dir / cache_file
        if file_path.exists():
            print_success(f"{cache_file:<20} - {description}")
        else:
            print_error(f"{cache_file:<20} - {description}")

def verify_monitoring() -> None:
    """验证监控"""
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}6. 监控模块验证{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    monitoring_files = [
        ("metrics.go", "Prometheus指标采集"),
        ("health.go", "健康检查"),
        ("middleware.go", "监控中间件"),
    ]
    
    monitoring_dir = PROJECT_ROOT / "internal/monitoring"
    
    for monitoring_file, description in monitoring_files:
        file_path = monitoring_dir / monitoring_file
        if file_path.exists():
            print_success(f"{monitoring_file:<20} - {description}")
        else:
            print_error(f"{monitoring_file:<20} - {description}")

def verify_database() -> None:
    """验证数据库"""
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}7. 数据库验证{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    # 检查迁移文件
    migration_files = [
        ("migrations/sqlite/V1__init.sql", "SQLite数据库迁移文件"),
    ]
    
    for migration_file, description in migration_files:
        file_path = PROJECT_ROOT / migration_file
        if file_path.exists():
            print_success(f"{migration_file:<50} - {description}")
            
            # 检查表定义
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            expected_tables = ["users", "roles", "permissions", "user_roles", "role_permissions", "devices", "login_logs", "operation_logs"]
            print(f"\n  {Colors.OKCYAN}数据表检查:{Colors.ENDC}")
            for table in expected_tables:
                if table in content:
                    print_success(f"    ✓ {table}")
                else:
                    print_error(f"    ✗ {table}")
        else:
            print_error(f"{migration_file:<50} - {description}")

def verify_config() -> None:
    """验证配置"""
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}8. 配置文件验证{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    config_files = [
        ("configs/config.yaml", "应用配置文件"),
        ("deployment/docker-compose.yml", "Docker Compose配置"),
        ("deployment/alertmanager/alertmanager.yml", "AlertManager配置"),
        ("deployment/alertmanager/alerts.yml", "告警规则"),
        ("deployment/grafana/dashboards/user-management.json", "Grafana仪表板"),
    ]
    
    for config_file, description in config_files:
        file_path = PROJECT_ROOT / config_file
        if file_path.exists():
            print_success(f"{config_file:<50} - {description}")
        else:
            print_error(f"{config_file:<50} - {description}")

def count_lines_of_code() -> Dict[str, int]:
    """统计代码行数"""
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}9. 代码统计{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    stats = {
        "total": 0,
        "go": 0,
        "sql": 0,
        "yaml": 0,
        "json": 0,
        "md": 0,
    }
    
    for file_path in PROJECT_ROOT.rglob("*"):
        if file_path.is_file():
            # 跳过特定目录
            if any(part in file_path.parts for part in [".git", "node_modules", "vendor", "__pycache__"]):
                continue
            
            ext = file_path.suffix.lower()
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    lines = len(f.readlines())
                
                stats["total"] += lines
                
                if ext == ".go":
                    stats["go"] += lines
                elif ext == ".sql":
                    stats["sql"] += lines
                elif ext in [".yaml", ".yml"]:
                    stats["yaml"] += lines
                elif ext == ".json":
                    stats["json"] += lines
                elif ext == ".md":
                    stats["md"] += lines
            except:
                pass
    
    print(f"{Colors.OKCYAN}总代码行数: {stats['total']:,}{Colors.ENDC}")
    print(f"  Go:     {stats['go']:,} 行")
    print(f"  SQL:    {stats['sql']:,} 行")
    print(f"  YAML:   {stats['yaml']:,} 行")
    print(f"  JSON:   {stats['json']:,} 行")
    print(f"  Markdown:{stats['md']:,} 行")
    
    return stats

def generate_report() -> Dict:
    """生成验证报告"""
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}10. 生成验证报告{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    # 运行所有验证
    total_files, exists_files, missing_files = verify_file_structure()
    service_results = verify_service_methods()
    handler_results = verify_handler_methods()
    verify_middleware()
    verify_cache()
    verify_monitoring()
    verify_database()
    verify_config()
    code_stats = count_lines_of_code()
    
    # 计算完成度
    file_completion = exists_files / total_files * 100
    
    service_total = sum(r["total"] for r in service_results.values() if r.get("exists"))
    service_found = sum(len(r.get("found", [])) for r in service_results.values() if r.get("exists"))
    service_completion = service_found / service_total * 100 if service_total > 0 else 0
    
    handler_total = sum(r["total"] for r in handler_results.values() if r.get("exists"))
    handler_found = sum(len(r.get("found", [])) for r in handler_results.values() if r.get("exists"))
    handler_completion = handler_found / handler_total * 100 if handler_total > 0 else 0
    
    overall_completion = (file_completion + service_completion + handler_completion) / 3
    
    # 打印总结
    print(f"\n{Colors.HEADER}{'='*60}{Colors.ENDC}")
    print(f"{Colors.HEADER}📊 验证总结{Colors.ENDC}")
    print(f"{Colors.HEADER}{'='*60}{Colors.ENDC}\n")
    
    print(f"{Colors.OKCYAN}文件结构:{Colors.ENDC} {file_completion:.1f}% ({exists_files}/{total_files})")
    print(f"{Colors.OKCYAN}Service层:{Colors.ENDC} {service_completion:.1f}% ({service_found}/{service_total})")
    print(f"{Colors.OKCYAN}Handler层:{Colors.ENDC} {handler_completion:.1f}% ({handler_found}/{handler_total})")
    print(f"{Colors.OKCYAN}代码总量:{Colors.ENDC} {code_stats['total']:,} 行")
    print(f"\n{Colors.BOLD}{Colors.OKGREEN}总体完成度: {overall_completion:.1f}%{Colors.ENDC}")
    
    if overall_completion >= 95:
        print(f"{Colors.OKGREEN}✓ 项目完整度优秀，可以进行验收！{Colors.ENDC}")
    elif overall_completion >= 80:
        print(f"{Colors.WARNING}⚠ 项目基本完成，但还有部分功能需要补充{Colors.ENDC}")
    else:
        print(f"{Colors.FAIL}✗ 项目完成度较低，需要继续完善{Colors.ENDC}")
    
    return {
        "file_completion": file_completion,
        "service_completion": service_completion,
        "handler_completion": handler_completion,
        "overall_completion": overall_completion,
        "total_files": total_files,
        "exists_files": exists_files,
        "missing_files": missing_files,
        "service_results": service_results,
        "handler_results": handler_results,
        "code_stats": code_stats,
    }

if __name__ == "__main__":
    print(f"{Colors.BOLD}{Colors.HEADER}")
    print("╔════════════════════════════════════════════════════════╗")
    print("║         用户管理系统 - 代码结构验证工具              ║")
    print("║              User Management System                   ║")
    print("╚════════════════════════════════════════════════════════╝")
    print(f"{Colors.ENDC}")
    
    try:
        report = generate_report()
        
        # 保存报告到JSON
        report_file = PROJECT_ROOT / "validation_report.json"
        with open(report_file, 'w', encoding='utf-8') as f:
            json.dump(report, f, indent=2, ensure_ascii=False)
        
        print(f"\n{Colors.OKCYAN}✓ 验证报告已保存到: {report_file}{Colors.ENDC}")
        
        # 退出码
        if report["overall_completion"] >= 95:
            sys.exit(0)
        else:
            sys.exit(1)
            
    except Exception as e:
        print(f"\n{Colors.FAIL}✗ 验证过程出错: {e}{Colors.ENDC}")
        sys.exit(1)
