package com.mosquito.project.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.Map;

/**
 * 统一API响应格式
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ApiResponse<T> {
    
    /**
     * HTTP状态码
     */
    private int code;
    
    /**
     * 响应消息
     */
    private String message;
    
    /**
     * 响应数据
     */
    private T data;
    
    /**
     * 元数据（分页等信息）
     */
    private Meta meta;
    
    /**
     * 错误信息
     */
    private Error error;
    
    /**
     * 时间戳
     */
    private LocalDateTime timestamp;
    
    /**
     * 请求追踪ID
     */
    private String traceId;

    public static <T> ApiResponse<T> success(T data) {
        return ApiResponse.<T>builder()
            .code(200)
            .message("success")
            .data(data)
            .timestamp(LocalDateTime.now())
            .build();
    }

    public static <T> ApiResponse<T> success(T data, String message) {
        return ApiResponse.<T>builder()
            .code(200)
            .message(message)
            .data(data)
            .timestamp(LocalDateTime.now())
            .build();
    }

    public static <T> ApiResponse<T> paginated(T data, int page, int size, long total) {
        Meta meta = Meta.createPagination(page, size, total);
        return ApiResponse.<T>builder()
            .code(200)
            .message("success")
            .data(data)
            .meta(meta)
            .timestamp(LocalDateTime.now())
            .build();
    }

    public static <T> ApiResponse<T> error(int code, String message) {
        return ApiResponse.<T>builder()
            .code(code)
            .message(message)
            .timestamp(LocalDateTime.now())
            .error(new Error(message))
            .build();
    }

    public static <T> ApiResponse<T> error(int code, String message, Object details) {
        return ApiResponse.<T>builder()
            .code(code)
            .message(message)
            .timestamp(LocalDateTime.now())
            .error(new Error(message, details))
            .build();
    }

    public static <T> ApiResponse<T> error(int code, String message, Object details, String traceId) {
        return ApiResponse.<T>builder()
            .code(code)
            .message(message)
            .timestamp(LocalDateTime.now())
            .error(new Error(message, details))
            .traceId(traceId)
            .build();
    }

    /**
     * 元数据基类
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Meta {
        private PaginationMeta pagination;
        private Map<String, Object> extra;

        public static Meta createPagination(int page, int size, long total) {
            Meta meta = new Meta();
            meta.setPagination(PaginationMeta.of(page, size, total));
            return meta;
        }
    }

    /**
     * 分页元数据
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class PaginationMeta {
        private int page;
        private int size;
        private long total;
        private int totalPages;
        private boolean hasNext;
        private boolean hasPrevious;

        public static PaginationMeta of(int page, int size, long total) {
            int totalPages = (int) Math.ceil((double) total / size);
            boolean hasNext = page < totalPages - 1;
            boolean hasPrevious = page > 0;
            
            return new PaginationMeta(page, size, total, totalPages, hasNext, hasPrevious);
        }
    }

    /**
     * 错误信息
     */
    @Data
    @NoArgsConstructor
    public static class Error {
        private String message;
        private Object details;
        private String code;

        public Error(String message) {
            this.message = message;
        }

        public Error(String message, Object details) {
            this.message = message;
            this.details = details;
        }

        public Error(String message, Object details, String code) {
            this.message = message;
            this.details = details;
            this.code = code;
        }
    }
}
