package com.fshark.overseas.advert;


import com.fshark.overseas.advert.modle.AppsFlyerEvent;
import com.fshark.overseas.advert.modle.EventTypeEnum;
import com.fshark.overseas.advert.modle.metrics.ActivationMetrics;
import com.fshark.overseas.advert.modle.metrics.EventMetrics;
import com.fshark.overseas.advert.processor.*;
import com.fshark.overseas.advert.util.AppConfig;
import org.apache.flink.api.common.restartstrategy.RestartStrategies;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer;

import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
 * 广告计算
 */
public class AppsflyerAnalyze {
    static AppConfig loadConfigFromArgs(String[] args) {
        ParameterTool parameters = ParameterTool.fromArgs(args);
        AppConfig appConfig = new AppConfig();
        try {
            appConfig.setSourceKafkaBootstrapServers(parameters.get("source-kafka-bootstrap-servers"));
            appConfig.setSourceKafkaGroupId(parameters.get("source-kafka-group-id"));
            appConfig.setSourceKafkaTopic(parameters.get("source-kafka-topic"));
//            appConfig.setStartOffsetTime(Long.valueOf(parameters.get("start-offset-time")));

            appConfig.setSinkKafkaBootstrapServers(parameters.get("sink-kafka-bootstrap-servers"));
            appConfig.setSinkKafkaTopic(parameters.get("sink-kafka-topic"));

            appConfig.setDbHost(parameters.get("jdbc-host"));
            appConfig.setDbUser(parameters.get("jdbc-user"));
            appConfig.setDbPassword(parameters.get("jdbc-password"));

        } catch (Exception e) {
            System.err.println("Place set args: " +
                    " --source-kafka-bootstrap-servers <source-kafka-bootstrap-servers>" +
                    " --source-kafka-group-id <source-kafka-group-id>" +
                    " --source-kafka-topic <source-kafka-topic>" +
                    " --sink-kafka-bootstrap-servers <sink-kafka-bootstrap-servers>" +
                    " --sink-kafka-group-id <sink-kafka-group-id>" +
                    " --sink-kafka-topic <sink-kafka-topic>" +
                    " --jdbc-host <jdbc-host> " +
                    " --jdbc-user <jdbc-user> " +
                    " --jdbc-password <jdbc-password> ");
            throw e;
        }
        return appConfig;
    }

    public static void main(String[] args) throws Exception {
        AppConfig appConfig = loadConfigFromArgs(args);
        final StreamExecutionEnvironment sse = StreamExecutionEnvironment.getExecutionEnvironment();
        sse.setParallelism(1);
        sse.enableCheckpointing(1000 * 60 * 10);
        sse.setRestartStrategy(RestartStrategies.fixedDelayRestart(Integer.MAX_VALUE, org.apache.flink.api.common.time.Time.of(10, TimeUnit.SECONDS)));

        //source设置
        Properties properties = new Properties();
        properties.setProperty("bootstrap.servers", appConfig.getSourceKafkaBootstrapServers());
        properties.setProperty("group.id", appConfig.getSourceKafkaGroupId());
        properties.setProperty("auto.offset.reset", "earliest");
        FlinkKafkaConsumer<String> dataConsumer = new FlinkKafkaConsumer<>(appConfig.getSourceKafkaTopic(), new SimpleStringSchema(), properties);
        // TODO: 2021/8/10  设置消费开始的时间戳1632326555000
//        if (appConfig.getStartOffsetTime() > 0) {
//            dataConsumer.setStartFromTimestamp(appConfig.getStartOffsetTime());
//        }

        Properties props2 = new Properties();
        props2.setProperty("bootstrap.servers", appConfig.getSinkKafkaBootstrapServers());
        FlinkKafkaProducer<String> kafkaSink = new FlinkKafkaProducer<>(appConfig.getSinkKafkaTopic(), new SimpleStringSchema(), props2);

        DataStream<AppsFlyerEvent> adEventDataStream = sse.addSource(dataConsumer)
                .flatMap(new ParseEventProcessor())
                .uid("parse-event")
                .name("parse-event")
                .shuffle();

        //广告指标(激活)
        DataStream<ActivationMetrics> activitionMetricStream = adEventDataStream
                .filter(EventTypeEnum::installEvent)
                .flatMap(new ActivitionProcess(appConfig))
                .uid("activition-event")
                .name("activition-event");


//        DataStream<ActivationMetrics> createRoleMetricStream = adEventDataStream
//                .filter(EventTypeEnum::createRoleEvent)
//                .flatMap(new CreateRoleProcess(appConfig))
//                .uid("create-role-event")
//                .name("create-role-event");

        //注册\留存 由于可能出现创角和角色登录是一瞬间的,所以他两合并计算
        DataStream<ActivationMetrics> loginRoleMetricStream = adEventDataStream
                .filter(EventTypeEnum::roleLoginEvent)
                .flatMap(new RoleLoginProcess(appConfig))
                .uid("role-login-event")
                .name("role-login-event");

        activitionMetricStream.union(loginRoleMetricStream)
                .flatMap(new ActivitionMetricToStringProcess(appConfig))
                .addSink(kafkaSink)
                .uid("sink-metric-event")
                .name("sink-metric-event");

//      订单信息
        adEventDataStream.filter(EventTypeEnum::orderEvent)
                .flatMap(new PurchaseToOrderDataProcessor(appConfig))
                .addSink(kafkaSink)
                .uid("order-event")
                .name("order-event");

        //区服 角色注册,激活
        adEventDataStream
                .filter(EventTypeEnum::roleEvent)
                .flatMap(new ServerActivationProcessor(appConfig))
                .flatMap(new ServerMtricToStringProcessor())
                .addSink(kafkaSink)
                .uid("activation-event")
                .name("activation-event");

        //事件统计激活
        adEventDataStream
                .filter(EventTypeEnum::notHeartBeatEvent)
                .flatMap(new EventMectrisProcessor(appConfig))
                .keyBy(EventMetrics::getKeys)
                .window(TumblingProcessingTimeWindows.of(Time.minutes(1)))
                .sum("times")
                .flatMap(new EventMetricsToStringProcessor())
                .addSink(kafkaSink)
                .uid("aggregate-event")
                .name("aggregate-event");

        sse.execute("appsflyer-analyze");

    }
}
