package com.bcxin.rest.web.apis;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.bcxin.api.interfaces.ApiConstant;
import com.bcxin.api.interfaces.identities.IdentityRpcProvider;
import com.bcxin.api.interfaces.rbacs.ISalaryArchiveService;
import com.bcxin.api.interfaces.rbacs.ISalaryChangeRecordService;
import com.bcxin.api.interfaces.rbacs.ISalaryConfigService;
import com.bcxin.api.interfaces.rbacs.ISalaryCurrentService;
import com.bcxin.api.interfaces.rbacs.ISalaryGroupService;
import com.bcxin.api.interfaces.rbacs.ISalaryItemService;
import com.bcxin.api.interfaces.rbacs.ISalaryPayrollService;
import com.bcxin.api.interfaces.rbacs.ISalaryReportService;
import com.bcxin.api.interfaces.rbacs.RbacCategoryRpcProvider;
import com.bcxin.api.interfaces.tenants.ContractRpcProvider;
import com.bcxin.api.interfaces.tenants.DepartAdminRpcProvider;
import com.bcxin.api.interfaces.tenants.DepartmentRpcProvider;
import com.bcxin.api.interfaces.tenants.EmployeeRpcProvider;
import com.bcxin.api.interfaces.tenants.OrganizationRpcProvider;
import com.bcxin.api.interfaces.tenants.ResourceRpcProvider;
import com.bcxin.api.interfaces.tenants.UserRpcProvider;

import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.schema.Example;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.ParameterType;
import springfox.documentation.service.RequestParameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@EnableSwagger2
@Configuration
@EnableDubbo
@ComponentScan(basePackages = {"com.bcxin.api.interfaces.tenants",
        "com.bcxin.api.interfaces.identities",
        "com.bcxin.api.interfaces.rbacs",
"com.bcxin.rest.web.commons"})
@Import({com.bcxin.web.commons.SetupConfig.class,
        com.bcxin.Infrastructures.InitConfig.class,
        com.bcxin.infrastructure.offices.OfficeInitConfig.class})
public class RestConfiguration {
    @DubboReference(check = false, version = ApiConstant.VERSION,retries = 0,
            methods = {
                    @Method(name = "signIn", onthrow = "rpcInvokeExceptionCallback.onThrow")
            })
    private final IdentityRpcProvider identityRpcProvider;


    @DubboReference(check = false, version = ApiConstant.VERSION,retries = 0,
            methods = {
                    @Method(name = "register", onthrow = "rpcInvokeExceptionCallback.onThrow")
            })
    private final OrganizationRpcProvider organizationRpcProvider;

    @DubboReference(check = false, version = ApiConstant.VERSION)
    private final DepartmentRpcProvider departmentRpcProvider;

    @DubboReference(check = false, version = ApiConstant.VERSION)
    private final EmployeeRpcProvider employeeRpcProvider;

    @DubboReference(check = false, version = ApiConstant.VERSION)
    private final UserRpcProvider userRpcProvider;

    @DubboReference(check = false, version = ApiConstant.VERSION)
    private final ResourceRpcProvider resourceRpcProvider;

    @DubboReference(check = false, version = ApiConstant.VERSION)
    private final DepartAdminRpcProvider departAdminRpcProvider;

    @DubboReference(check = false, version = ApiConstant.VERSION)
    private final ContractRpcProvider contractRpcProvider;

    @DubboReference(check = false, version = ApiConstant.VERSION)
    private final RbacCategoryRpcProvider rbacCategoryRpcProvider;
    
    @DubboReference(check = false, version = ApiConstant.VERSION)
    private  ISalaryArchiveService salaryArchiveService ;
    
    @DubboReference(check = false, version = ApiConstant.VERSION)
    private  ISalaryChangeRecordService salaryChangeRecordService ;
    
    @DubboReference(check = false, version = ApiConstant.VERSION)
    private  ISalaryGroupService salaryGroupService ;
    
    @DubboReference(check = false, version = ApiConstant.VERSION)
    private  ISalaryConfigService salaryConfigService ;
    
    @DubboReference(check = false, version = ApiConstant.VERSION)
    private  ISalaryItemService salaryItemService ;
    
    @DubboReference(check = false, version = ApiConstant.VERSION)
    private  ISalaryCurrentService salaryCurrentService ;
    
    @DubboReference(check = false, version = ApiConstant.VERSION)
    private  ISalaryReportService salaryReportService ;
    
    @DubboReference(check = false, version = ApiConstant.VERSION)
    private  ISalaryPayrollService salaryPayrollService ;
    
    

    public RestConfiguration(IdentityRpcProvider identityRpcProvider,
                             OrganizationRpcProvider organizationRpcProvider,
                             DepartmentRpcProvider departmentRpcProvider,
                             EmployeeRpcProvider employeeRpcProvider,
                             UserRpcProvider userRpcProvider,
                             ResourceRpcProvider resourceRpcProvider,
                             DepartAdminRpcProvider departAdminRpcProvider,
                             ContractRpcProvider contractRpcProvider, 
                             RbacCategoryRpcProvider rbacCategoryRpcProvider,
                             ISalaryArchiveService salaryArchiveService) {
        this.identityRpcProvider = identityRpcProvider;
        this.organizationRpcProvider = organizationRpcProvider;
        this.departmentRpcProvider = departmentRpcProvider;
        this.employeeRpcProvider = employeeRpcProvider;
        this.userRpcProvider = userRpcProvider;
        this.resourceRpcProvider = resourceRpcProvider;
        this.departAdminRpcProvider = departAdminRpcProvider;
        this.contractRpcProvider = contractRpcProvider;
        this.rbacCategoryRpcProvider = rbacCategoryRpcProvider;
    }

    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter() {
            @Override
            protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
                super.writeInternal(object, outputMessage);
            }
        };
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.PrettyFormat,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteNullBooleanAsFalse
        );
        fastJsonConfig.setDateFormat("yyyy-MM-dd");
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
        return new HttpMessageConverters(fastJsonHttpMessageConverter);
    }

    @Bean
    public Docket api() {
        String description = "<h3>百川信企业租户管理平台</h3>" +
                "<dev>该租户API支撑:" +
                "<ul>" +
                "<li><span>统一认证中心</span>" +
                "<ul>" +
                "<li>账号密码登入</li>" +
                "<li>微信一键登入</li>" +
                "<li>其他登入</li>" +
                "</ul>" +
                "</li>" +
                "<li>密码管理</li>" +
                "<li>一人入驻多企业</li>" +
                "<li>一人创办多企业</li>" +
                "<li><span>部门管理</span>" +
                "<ul>" +
                "<li>企业管理员</li>" +
                "<li>部门管理员</li>" +
                "<li>其他登入</li>" +
                "</ul>" +
                "</li>" +
                "<li>通讯录授权管理</li>" +
                "<li>企业切换</li>" +
                "<li>企业行业信息管理</li>" +
                "<li>企业信息个人偏好设置</li>" +
                "</ul></dev>";
        ApiInfo apiInfo = new ApiInfo("百川信企业租户管理平台 API", description, "1.0", "", new Contact("", "", ""),
                "", "", Collections.EMPTY_LIST);

        List<RequestParameter> globalOperationParams = new ArrayList<>();

        RequestParameterBuilder builder = new RequestParameterBuilder();
        RequestParameter parameter = builder
                .name("Authorization").example(new Example("1", "Bearer认证模式", "Bearer认证模式", "Bearer xxxxxxxxxxx", "", "Authorization"))
                .description("当前用户的认证信息")
                .in(ParameterType.HEADER)
                .build();
        globalOperationParams.add(parameter);


        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(it -> {
                    return !it.getName().startsWith("error");
                }).paths(PathSelectors.any())
                .build()
                .apiInfo(apiInfo)
                .consumes(Collections.singleton("application/json"))
                .globalRequestParameters(globalOperationParams);
    }

    @Bean
    public UiConfiguration uiConfiguration() {
        return UiConfigurationBuilder.builder()
                .defaultModelExpandDepth(0)
                .defaultModelsExpandDepth(-1)
                .build();
    }

    @Bean
    public FilterRegistrationBean corsFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // 允许cookies跨域
        config.addAllowedOriginPattern("*");
//        config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI，*表示全部允许，在SpringMVC中，如果设成*，会自动转成当前请求头中的Origin
        config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
        config.setMaxAge(18000L);// 预检请求的缓存时间（秒），即在这个时间段里，对于相同的跨域请求不会再预检了
        config.addAllowedMethod("*");// 允许提交请求的方法，*表示全部允许
        source.registerCorsConfiguration("/**", config);
        filterRegistrationBean.setFilter(new CorsFilter(source) {
            @Override
            protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                    throws ServletException, IOException {
                System.err.println(String.format("CORSxx DEBUG:%s", request.getRequestURI()));
                super.doFilterInternal(request, response, filterChain);
            }
        });
        filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);

        return filterRegistrationBean;
    }
}










