/*
 * Copyright 2015-present Open Networking Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onosproject.cli.net;

import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Streams;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.LinkKey;
import org.onosproject.net.Port;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.device.PortStatistics;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.ObjectiveTrackerService;
import org.onosproject.net.intent.PointToPointIntent;
import org.onosproject.net.intent.WorkPartitionService;
import org.onosproject.net.statistic.FlowStatisticService;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;

@Command(scope = "onos", name = "intents-diagnosis",
        description = "Diagnosis intents")
public class IntentsDiagnosisCommand extends AbstractShellCommand {

    @Argument(index = 0, name = "key",
            description = "Intent key",
            required = false, multiValued = false)
    String key = null;

    @Option(name = "-d", aliases = "--details", description = "printing intent details",
            required = false, multiValued = false)
    private boolean dump = false;

    @Option(name = "-l", aliases = "--link", description = "printing local intentsByLink",
            required = false, multiValued = false)
    private boolean dumpIntentByLink = false;

    private static final int MAX_INTENT_PATH = 100;
    private static final String FIELD_INTENTS_BY_LINK = "intentsByLink";

    @Override
    protected void execute() {

        print("intents-diagnosis");
        ServiceRefs svcRefs = buildServiceRefs();
        if (svcRefs == null) {
            return;
        }
        try {
            for (Intent intent : svcRefs.intentsService().getIntents()) {
                if (key != null && !intent.key().toString().equals(key)) {
                    continue;
                }
                print("");
                printIntentHdr(intent, svcRefs);
                if (intent instanceof PointToPointIntent) {
                    diagnosisP2Pintent((PointToPointIntent) intent, svcRefs);
                } else {
                    // TODO : it needs to implement other types of intent
                    print(" It doesn't support %s intent.", intent.getClass().getSimpleName());
                }
            }
            if (dumpIntentByLink) {
                dumpIntentsByLink(svcRefs);
            }
        } catch (Exception e) {
            print("error: " + e);
        }

    }

    private void printIntentHdr(Intent intent, ServiceRefs svcRefs) {
        print("* intent key: %s", intent.key());
        print(" - state: %s", svcRefs.intentsService().getIntentState(intent.key()));
        dump(" - leader: %s %s", svcRefs.getWorkPartitionService().getLeader(intent.key(), Key::hash),
                svcRefs.workPartitionService.isMine(intent.key(), Key::hash) ? "(Mine)" : "");
    }

    private void dumpIntentsByLink(ServiceRefs svcRefs) {
        Set<Map.Entry<LinkKey, Key>> intentsByLink = getIntentsByLinkSet(svcRefs);

        print("* intentsbylink:");
        for (Map.Entry<LinkKey, Key> entry : intentsByLink) {
            print(" - %s, Intents: %s ", entry.getKey(), entry.getValue());
        }
    }

    private Set<Map.Entry<LinkKey, Key>> getIntentsByLinkSet(ServiceRefs svcRefs) {

        try {

            ObjectiveTrackerService objTracker = svcRefs.getObjectiveTrackerService();

            // Utilizing reflection instead of adding new interface for getting intentsByLink
            Field f = objTracker.getClass().getDeclaredField(FIELD_INTENTS_BY_LINK);
            f.setAccessible(true);
            SetMultimap<LinkKey, Key> intentsByLink = (SetMultimap<LinkKey, Key>) f.get(objTracker);

            return ImmutableSet.copyOf(intentsByLink.entries());
        } catch (NoSuchFieldException | IllegalAccessException ex) {
            error("error: " + ex);
            return ImmutableSet.of();
        }
    }

    private void diagnosisP2Pintent(PointToPointIntent intent, ServiceRefs svcRefs) {

        List<Intent> installableIntents = svcRefs.intentsService().getInstallableIntents(intent.key());

        if (installableIntents.size() == 0) {
            error("NO INSTALLABLE INTENTS");
            return;
        }

        Set<String> notSupport = new HashSet<>();
        for (Intent installable: installableIntents) {
            if (installable instanceof FlowRuleIntent) {
                checkP2PFlowRuleIntent(intent, (FlowRuleIntent) installable, svcRefs);
            } else {
                // TODO : it needs to implement other types of installables
                notSupport.add(installable.getClass().getSimpleName());
            }
        }

        if (notSupport.size() > 0) {
            print(" It doesn't support %s.", notSupport);
        }
    }

    private void checkP2PFlowRuleIntent(PointToPointIntent intent, FlowRuleIntent installable, ServiceRefs svcRefs) {

        final Map<DeviceId, DeviceOnIntent> devs = createDevicesOnP2PIntent(intent, installable);

        boolean errorOccurred = false;
        // checking the number of links & CPs in P2P intent
        for (DeviceOnIntent dev: devs.values()) {
            if (dev.getIngressLinks().size() > 1) {
                error("MULTIPLE NUMBER OF INGRESS LINKs on " + dev.deviceId()
                        + ": " + dev.getIngressLinks());
                errorOccurred = true;
            }
            if (dev.getIngressCps().size() > 1) {
                error("MULTIPLE NUMBER OF INGRESS CONNECT POINTs on " + dev.deviceId()
                        + ": " + dev.getIngressCps());
                errorOccurred = true;
            }
            if (dev.getEgressLinks().size() > 1) {
                error("MULTIPLE NUMBER OF EGRESS LINKs: on " + dev.deviceId()
                        + ": " + dev.getEgressLinks());
                errorOccurred = true;
            }
            if (dev.getEgressCps().size() > 1) {
                error("MULTIPLE NUMBER OF EGRESS CONNECT POINTs: on " + dev.deviceId()
                        + ": " + dev.getEgressCps());
                errorOccurred = true;
            }
        }

        ConnectPoint startCp = intent.filteredIngressPoint().connectPoint();
        DeviceOnIntent startDev = devs.get(startCp.deviceId());
        if (startDev == null) {
            error("STARTING CONNECT POINT DEVICE: " + startCp.deviceId() + " is not on intent");
            errorOccurred = true;
        }

        ConnectPoint endCp = intent.filteredEgressPoint().connectPoint();
        DeviceOnIntent endDev = devs.get(endCp.deviceId());
        if (endDev == null) {
            error("END CONNECT POINT DEVICE: " + endCp.deviceId() + " is not on intent");
            errorOccurred = true;
        }

        if (!errorOccurred) {
            // Per device checking with path-order
            DeviceOnIntent dev = startDev;
            int i = 0;
            for (; i < MAX_INTENT_PATH; i++) {
                perDeviceChecking(dev, svcRefs);

                // P2P intent has only 1 egress CP
                ConnectPoint egressCp = dev.getEgressCps().stream().findFirst().orElse(null);
                if (egressCp != null && Objects.equals(endCp, egressCp)) {
                    break;
                }

                // P2P intent has only 1 egress link
                Link egressLink = dev.getEgressLinks().stream().findFirst().orElse(null);
                if (egressLink == null) {
                    error("INVALID EGRESS LINK & CONNECT POINT for: " + dev);
                    errorOccurred = true;
                    break;
                }
                if (Objects.equals(egressLink.dst(), endCp)) {
                    break;
                }

                // P2P intent only 1 ingress link
                dev = devs.values().stream()
                        .filter(nextDev -> Objects.equals(
                            egressLink, nextDev.getIngressLinks().stream().findFirst().orElse(null)))
                        .findAny().orElse(null);
                if (dev == null) {
                    error("FAILED TO FIND NEXT DEV for: " + dev + ", LINK: " + egressLink);
                    errorOccurred = true;
                    break;
                }
            }
            if (i == MAX_INTENT_PATH) {
                error("MAX INTENT PATH WAS EXCEEDED");
                errorOccurred = true;
            }
        }

        if (errorOccurred) {
            // Installable checking
            dump("");
            dump("ERROR OCCURRED. DO PER FLOW CHECKING");
            perFlowRuleChecking(installable, svcRefs);
        }

        if (svcRefs.workPartitionService.isMine(intent.key(), Key::hash)) {
            checkIntentsByLink(installable, svcRefs);
        }
    }

    private void checkIntentsByLink(FlowRuleIntent installable, ServiceRefs svcRefs) {

        Set<Map.Entry<LinkKey, Key>> intentsByLink = getIntentsByLinkSet(svcRefs);

        installable.resources().forEach(
                rsrc -> {
                    if (rsrc instanceof Link) {
                        Link link = (Link) rsrc;
                        LinkKey linkKey = LinkKey.linkKey(link);
                        intentsByLink.stream()
                                .filter(entry -> Objects.equals(entry.getKey(), linkKey)
                                        && Objects.equals(entry.getValue(), installable.key()))
                                .findAny()
                                .orElseGet(() -> {
                                    error("FAILED TO FIND LINK(" + link + ") for intents: " + installable.key());
                                    return null;
                                });
                    }
                }
        );
    }

    // TODO: It needs to consider FLowObjectiveIntent case
    private void perDeviceChecking(DeviceOnIntent devOnIntent, ServiceRefs svcRefs) {

        Collection<PortStatistics> portStats =
                svcRefs.deviceService().getPortStatistics(devOnIntent.deviceId());
        Collection<PortStatistics> portDeltaStats =
                svcRefs.deviceService().getPortDeltaStatistics(devOnIntent.deviceId());

        dump("");
        dump(" ------------------------------------------------------------------------------------------");

        Device device = svcRefs.deviceService.getDevice(devOnIntent.deviceId());
        if (device == null) {
            error("INVALID DEVICE for " + devOnIntent.deviceId());
            return;
        }

        dump(" %s", getDeviceString(device));
        dump("  %s", device.annotations());

        devOnIntent.getIngressCps().stream()
                .forEach(cp -> dumpCpStatistics(cp, portStats, portDeltaStats, "INGRESS", svcRefs));

        Stream<FlowEntry> flowEntries = Streams.stream(svcRefs.flowService.getFlowEntries(devOnIntent.deviceId()));

        devOnIntent.getFlowRules().stream()
                .forEach(
                        intentFlowRule -> {
                            FlowEntry matchedEntry = flowEntries
                                    .filter(entry -> Objects.equals(intentFlowRule.id(), entry.id()))
                                    .findFirst().orElse(null);

                            if (matchedEntry == null) {
                                error("FAILED TO FIND FLOW ENTRY: for " + intentFlowRule);
                                return;
                            }

                            if (Objects.equals(intentFlowRule.selector(), matchedEntry.selector()) &&
                                    Objects.equals(intentFlowRule.treatment(), matchedEntry.treatment())) {
                                dumpFlowEntry(matchedEntry, "FLOW ENTRY");
                                return;
                            }

                            error("INSTALLABLE-FLOW ENTRY mismatch");
                            dumpFlowRule(intentFlowRule, "INSTALLABLE");
                            dumpFlowEntry(matchedEntry, "FLOW ENTRY");
                        }
                );

        devOnIntent.getEgressCps().stream()
                .forEach(
                        cp -> dumpCpStatistics(cp, portStats, portDeltaStats, "EGRESS", svcRefs)
                );
    }

    // TODO: It needs to consider FLowObjectiveIntent case
    private void perFlowRuleChecking(FlowRuleIntent installable, ServiceRefs svcRefs) {

        installable.flowRules().forEach(
                flowrule -> {
                    DeviceId devId = flowrule.deviceId();
                    if (devId == null) {
                        error("INVALID DEVICE ID for " + flowrule);
                        return;
                    }

                    Device dev = svcRefs.deviceService.getDevice(devId);
                    if (dev == null) {
                        error("INVALID DEVICE for " + flowrule);
                        return;
                    }

                    dump("");
                    dump(
                    " ------------------------------------------------------------------------------------------");
                    dump(" %s", getDeviceString(dev));
                    dump("  %s", dev.annotations());

                    svcRefs.flowService().getFlowEntries(devId)
                            .forEach(
                                    entry -> {
                                        dumpFlowRule(flowrule, "INSTALLABLE");
                                        dumpFlowEntry(entry, "FLOW ENTRY");

                                        if (!flowrule.selector().equals(entry.selector())) {
                                            return;
                                        }
                                        if (flowrule.id().equals(entry.id()) &&
                                                flowrule.treatment().equals(entry.treatment())) {
                                            dumpFlowEntry(entry, "FLOW ENTRY");
                                            return;
                                        }
                                        error("INSTALLABLE-FLOW ENTRY mismatch");
                                    }
                            );
                }
        );
    }

    private Map<DeviceId, DeviceOnIntent> createDevicesOnP2PIntent(
            PointToPointIntent intent, FlowRuleIntent flowRuleIntent) {

        final Map<DeviceId, DeviceOnIntent> devMap = new HashMap<>();

        flowRuleIntent.resources().forEach(
                rsrc -> {
                    if (rsrc instanceof Link) {
                        Link link = (Link) rsrc;
                        ConnectPoint srcCp = link.src();
                        ConnectPoint dstCp = link.dst();
                        try {
                            DeviceOnIntent dev = devMap.computeIfAbsent(srcCp.deviceId(), DeviceOnIntent::new);
                            dev.addEgressLink(link);

                            dev = devMap.computeIfAbsent(dstCp.deviceId(), DeviceOnIntent::new);
                            dev.addIngressLink(link);
                        } catch (IllegalStateException e) {
                            print("error: " + e);
                        }
                    }
                }
        );

        ConnectPoint startCp = intent.filteredIngressPoint().connectPoint();
        DeviceOnIntent startDev = devMap.computeIfAbsent(startCp.deviceId(), DeviceOnIntent::new);
        if (!startDev.hasIngressCp(startCp)) {
            startDev.addIngressCp(startCp);
        }

        ConnectPoint endCp = intent.filteredEgressPoint().connectPoint();
        DeviceOnIntent endDev = devMap.computeIfAbsent(endCp.deviceId(), DeviceOnIntent::new);
        if (!endDev.hasEgressCp(endCp)) {
            endDev.addEgessCp(endCp);
        }

        flowRuleIntent.flowRules().forEach(
                flowRule -> {
                    DeviceId devId = flowRule.deviceId();
                    if (devId == null) {
                        error("INVALID DEVICE ID for " + flowRule);
                        return;
                    }
                    DeviceOnIntent dev = devMap.get(devId);
                    if (dev == null) {
                        error("DEVICE(" + devId + ") IS NOT ON INTENTS LINKS");
                        return;
                    }

                    dev.addFlowRule(flowRule);
                }
        );

        return devMap;
    }

    private String getDeviceString(Device dev) {

        StringBuilder buf = new StringBuilder();
        if (dev != null) {
            buf.append(String.format("Device: %s, ", dev.id()));
            buf.append(String.format("%s, ", dev.type()));
            buf.append(String.format("%s, ", dev.manufacturer()));
            buf.append(String.format("%s, ", dev.hwVersion()));
            buf.append(String.format("%s, ", dev.swVersion()));
            if (dev instanceof DefaultDevice) {
                DefaultDevice dfltDev = (DefaultDevice) dev;
                if (dfltDev.driver() != null) {
                    buf.append(String.format("%s, ", dfltDev.driver().name()));
                }
                String channelId = dfltDev.annotations().value("channelId");
                if (channelId != null) {
                    buf.append(String.format("%s, ", channelId));
                }
            }
        }

        return buf.toString();
    }

    private void dumpFlowRule(FlowRule rule, String hdr) {
        dump("  " + hdr + ":");
        dump("   - id=%s, priority=%d", rule.id(), rule.priority());
        dump("   - %s", rule.selector());
        dump("   - %s", rule.treatment());
    }

    private void dumpFlowEntry(FlowEntry entry, String hdr) {
        dumpFlowRule(entry, hdr);
        dump("   - packets=%d", entry.packets());
    }


    private void dumpCpStatistics(ConnectPoint cp, Collection<PortStatistics> devPortStats,
                                  Collection<PortStatistics> devPortDeltaStats, String direction, ServiceRefs svcs) {
        if (cp == null) {
            return;
        }

        dump("  %s:", direction);

        if (cp.port().isLogical()) {
            dump("   - logical: device: %s, port: %s", cp.deviceId(), cp.port());
            return;
        }

        Port port =  svcs.deviceService.getPort(cp.deviceId(), cp.port());
        if (port == null) {
            return;
        }

        try {
            devPortStats.stream()
                    .filter(stat -> stat.portNumber().equals(cp.port()))
                    .forEach(stat -> dump("   - stat   : %s:", getPortStatStr(stat, port)));
        } catch (IllegalStateException e) {
            error("error: " + e);
            return;
        }

        try {
            devPortDeltaStats.stream()
                    .filter(stat -> stat.portNumber().equals(cp.port()))
                    .forEach(stat -> dump("   - delta  : %s:", getPortStatStr(stat, port)));
        } catch (IllegalStateException e) {
            error("error: " + e);
        }
    }

    private void dump(String format, Object ... args) {
        if (dump) {
            print(format, args);
        }
    }

    private String getPortStatStr(PortStatistics stat, Port port) {

        final String portName = port.annotations().value(AnnotationKeys.PORT_NAME);

        return String.format("port: %s(%s), ", stat.portNumber(), portName) +
                String.format("enabled: %b, ", port.isEnabled()) +
                String.format("pktRx: %d, ", stat.packetsReceived()) +
                String.format("pktTx: %d, ", stat.packetsSent()) +
                String.format("pktRxErr: %d, ", stat.packetsRxErrors()) +
                String.format("pktTxErr: %d, ", stat.packetsTxErrors()) +
                String.format("pktRxDrp: %d, ", stat.packetsRxDropped()) +
                String.format("pktTxDrp: %d", stat.packetsTxDropped());
    }

    private static class DeviceOnIntent {

        private final DeviceId devId;

        private Collection<Link> ingressLinks = new ArrayList<>();

        private Collection<Link> egressLinks = new ArrayList<>();

        private Collection<ConnectPoint> ingressCps = new ArrayList<>();

        private Collection<ConnectPoint> egressCps = new ArrayList<>();

        private Collection<FlowRule> flowRules = new ArrayList<>();

        public DeviceOnIntent(DeviceId devId) {
            this.devId = devId;
        }

        public DeviceId deviceId() {
            return devId;
        }

        public Collection<Link> getIngressLinks() {
            return ingressLinks;
        }

        public Collection<Link> getEgressLinks() {
            return egressLinks;
        }

        public void addIngressLink(Link link) {
            ingressLinks.add(link);
            addIngressCp(link.dst());
        }

        public void addEgressLink(Link link) {
            egressLinks.add(link);
            addEgessCp(link.src());
        }

        public void addIngressCp(ConnectPoint cp) {
            ingressCps.add(cp);
        }

        public void addEgessCp(ConnectPoint cp) {
            egressCps.add(cp);
        }

        public boolean hasIngressCp(final ConnectPoint cp) {
            return ingressCps.stream().anyMatch(icp -> Objects.equals(icp, cp));
        }

        public boolean hasEgressCp(ConnectPoint cp) {
            return egressCps.stream().anyMatch(ecp -> Objects.equals(ecp, cp));
        }

        public Collection<ConnectPoint> getIngressCps() {
            return ingressCps;
        }

        public Collection<ConnectPoint> getEgressCps() {
            return egressCps;
        }

        public Collection<FlowRule> getFlowRules() {
            return flowRules;
        }

        public void addFlowRule(FlowRule flowRule) {
            flowRules.add(flowRule);
        }

        public String toString() {
            return MoreObjects.toStringHelper(getClass())
                    .omitNullValues()
                    .add("devId", devId)
                    .add("ingressLinks", ingressLinks)
                    .add("egressLinks", egressLinks)
                    .add("flowRules", flowRules)
                    .toString();
        }
    }


    private ServiceRefs buildServiceRefs() {
        IntentService intentsService = get(IntentService.class);
        if (intentsService == null) {
            return null;
        }
        DeviceService deviceService = get(DeviceService.class);
        if (deviceService == null) {
            return null;
        }
        FlowStatisticService flowStatsService = get(FlowStatisticService.class);
        if (flowStatsService == null) {
            return null;
        }
        FlowRuleService flowService = get(FlowRuleService.class);
        if (flowService == null) {
            return null;
        }
        WorkPartitionService workPartitionService = get(WorkPartitionService.class);
        if (workPartitionService == null) {
            return null;
        }
        ObjectiveTrackerService objectiveTrackerService = get(ObjectiveTrackerService.class);
        if (objectiveTrackerService == null) {
            return null;
        }

        return new ServiceRefs(
                intentsService,
                deviceService,
                flowService,
                workPartitionService,
                objectiveTrackerService
        );
    }

    private static final class ServiceRefs {

        private IntentService intentsService;
        private DeviceService deviceService;
        private FlowRuleService flowService;
        private WorkPartitionService workPartitionService;
        private ObjectiveTrackerService objectiveTrackerService;

        private ServiceRefs(
                IntentService intentsService,
                DeviceService deviceService,
                FlowRuleService flowService,
                WorkPartitionService workPartitionService,
                ObjectiveTrackerService objectiveTrackerService
        ) {
            this.intentsService = intentsService;
            this.deviceService = deviceService;
            this.flowService = flowService;
            this.workPartitionService = workPartitionService;
            this.objectiveTrackerService = objectiveTrackerService;
        }

        public IntentService intentsService() {
            return intentsService;
        }

        public DeviceService deviceService() {
            return deviceService;
        }

        public FlowRuleService flowService() {
            return flowService;
        }

        public WorkPartitionService getWorkPartitionService() {
            return workPartitionService;
        }

        public ObjectiveTrackerService getObjectiveTrackerService() {
            return objectiveTrackerService;
        }
    }

}
