/*
 * Copyright 2016-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.segmentrouting;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalCause;
import com.google.common.cache.RemovalNotification;
import com.google.common.collect.Sets;

import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.HostLocation;
import org.onosproject.net.PortNumber;
import org.onosproject.net.host.HostEvent;
import org.onosproject.routeservice.ResolvedRoute;
import org.onosproject.routeservice.RouteEvent;
import org.onosproject.net.DeviceId;
import org.onosproject.routeservice.RouteInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Handles RouteEvent and manages routing entries.
 */
public class RouteHandler {
    private static final Logger log = LoggerFactory.getLogger(RouteHandler.class);
    private final SegmentRoutingManager srManager;

    private static final int WAIT_TIME_MS = 1000;
    /**
     * The routeEventCache is implemented to avoid race condition by giving more time to the
     * underlying flow subsystem to process previous populateSubnet call.
     */
    private Cache<IpPrefix, RouteEvent> routeEventCache = CacheBuilder.newBuilder()
            .expireAfterWrite(WAIT_TIME_MS, TimeUnit.MILLISECONDS)
            .removalListener((RemovalNotification<IpPrefix, RouteEvent> notification) -> {
                IpPrefix prefix = notification.getKey();
                RouteEvent routeEvent = notification.getValue();
                RemovalCause cause = notification.getCause();
                log.debug("routeEventCache removal event. prefix={}, routeEvent={}, cause={}",
                        prefix, routeEvent, cause);

                switch (notification.getCause()) {
                    case REPLACED:
                    case EXPIRED:
                        dequeueRouteEvent(routeEvent);
                        break;
                    default:
                        break;
                }
            }).build();

    RouteHandler(SegmentRoutingManager srManager) {
        this.srManager = srManager;

        Executors.newSingleThreadScheduledExecutor()
                .scheduleAtFixedRate(routeEventCache::cleanUp, 0, WAIT_TIME_MS, TimeUnit.MILLISECONDS);
    }

    protected void init(DeviceId deviceId) {
        Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(deviceId);

        srManager.routeService.getRouteTables().stream()
                .map(srManager.routeService::getRoutes)
                .flatMap(Collection::stream)
                .map(RouteInfo::allRoutes)
                .filter(allRoutes -> allRoutes.stream().allMatch(resolvedRoute ->
                        srManager.nextHopLocations(resolvedRoute).stream().allMatch(cp ->
                            deviceId.equals(cp.deviceId()) ||
                                    (pairDeviceId.isPresent() && pairDeviceId.get().equals(cp.deviceId()))
                        )))
                .forEach(this::processRouteAddedInternal);
    }

    void processRouteAdded(RouteEvent event) {
        enqueueRouteEvent(event);
    }

    private void processRouteAddedInternal(Collection<ResolvedRoute> routes) {
        if (!isReady()) {
            log.info("System is not ready. Skip adding route for {}", routes);
            return;
        }

        log.info("processRouteAddedInternal. routes={}", routes);

        if (routes.size() > 2) {
            log.info("Route {} has more than two next hops. Do not process route change", routes);
            return;
        }

        Set<ConnectPoint> allLocations = Sets.newHashSet();
        Set<IpPrefix> allPrefixes = Sets.newHashSet();
        routes.forEach(route -> {
            allLocations.addAll(srManager.nextHopLocations(route));
            allPrefixes.add(route.prefix());
        });
        log.debug("RouteAdded. populateSubnet {}, {}", allLocations, allPrefixes);
        srManager.defaultRoutingHandler.populateSubnet(allLocations, allPrefixes);

        routes.forEach(route -> {
            IpPrefix prefix = route.prefix();
            MacAddress nextHopMac = route.nextHopMac();
            VlanId nextHopVlan = route.nextHopVlan();
            Set<ConnectPoint> locations = srManager.nextHopLocations(route);

            locations.forEach(location -> {
                log.debug("RouteAdded. addSubnet {}, {}", location, prefix);
                srManager.deviceConfiguration.addSubnet(location, prefix);
                log.debug("RouteAdded populateRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
                srManager.defaultRoutingHandler.populateRoute(location.deviceId(), prefix,
                        nextHopMac, nextHopVlan, location.port());
            });
        });
    }

    void processRouteUpdated(RouteEvent event) {
        enqueueRouteEvent(event);
    }

    void processAlternativeRoutesChanged(RouteEvent event) {
        enqueueRouteEvent(event);
    }

    private void processRouteUpdatedInternal(Set<ResolvedRoute> routes, Set<ResolvedRoute> oldRoutes) {
        if (!isReady()) {
            log.info("System is not ready. Skip updating route for {} -> {}", oldRoutes, routes);
            return;
        }

        log.info("processRouteUpdatedInternal. routes={}, oldRoutes={}", routes, oldRoutes);

        if (routes.size() > 2) {
            log.info("Route {} has more than two next hops. Do not process route change", routes);
            return;
        }

        Set<ConnectPoint> allLocations = Sets.newHashSet();
        Set<IpPrefix> allPrefixes = Sets.newHashSet();
        routes.forEach(route -> {
            allLocations.addAll(srManager.nextHopLocations(route));
            allPrefixes.add(route.prefix());
        });

        // Just come back from an invalid next hop count
        // Revoke subnet from all locations and reset oldRoutes such that system will be reprogrammed from scratch
        if (oldRoutes.size() > 2) {
            log.info("Revoke subnet {} and reset oldRoutes");
            srManager.defaultRoutingHandler.revokeSubnet(allPrefixes);
            oldRoutes = Sets.newHashSet();
        }

        log.debug("RouteUpdated. populateSubnet {}, {}", allLocations, allPrefixes);
        srManager.defaultRoutingHandler.populateSubnet(allLocations, allPrefixes);

        Set<ResolvedRoute> toBeRemoved = Sets.difference(oldRoutes, routes).immutableCopy();
        Set<ResolvedRoute> toBeAdded = Sets.difference(routes, oldRoutes).immutableCopy();

        toBeRemoved.forEach(route -> {
            srManager.nextHopLocations(route).forEach(oldLocation -> {
                if (toBeAdded.stream().map(srManager::nextHopLocations)
                        .flatMap(Set::stream).map(ConnectPoint::deviceId)
                        .noneMatch(deviceId -> deviceId.equals(oldLocation.deviceId()))) {
                    IpPrefix prefix = route.prefix();
                    log.debug("RouteUpdated. removeSubnet {}, {}", oldLocation, prefix);
                    srManager.deviceConfiguration.removeSubnet(oldLocation, prefix);
                    // We don't remove the flow on the old location in occasion of two next hops becoming one
                    // since the populateSubnet will point the old location to the new location via spine.
                }
            });
        });

        toBeAdded.forEach(route -> {
            IpPrefix prefix = route.prefix();
            MacAddress nextHopMac = route.nextHopMac();
            VlanId nextHopVlan = route.nextHopVlan();
            Set<ConnectPoint> locations = srManager.nextHopLocations(route);

            locations.forEach(location -> {
                log.debug("RouteUpdated. addSubnet {}, {}", location, prefix);
                srManager.deviceConfiguration.addSubnet(location, prefix);
                log.debug("RouteUpdated. populateRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
                srManager.defaultRoutingHandler.populateRoute(location.deviceId(), prefix,
                        nextHopMac, nextHopVlan, location.port());
            });
        });
    }

    void processRouteRemoved(RouteEvent event) {
        enqueueRouteEvent(event);
    }

    private void processRouteRemovedInternal(Collection<ResolvedRoute> routes) {
        if (!isReady()) {
            log.info("System is not ready. Skip removing route for {}", routes);
            return;
        }

        log.info("processRouteRemovedInternal. routes={}", routes);

        Set<IpPrefix> allPrefixes = Sets.newHashSet();
        routes.forEach(route -> {
            allPrefixes.add(route.prefix());
        });
        log.debug("RouteRemoved. revokeSubnet {}", allPrefixes);
        srManager.defaultRoutingHandler.revokeSubnet(allPrefixes);

        routes.forEach(route -> {
            IpPrefix prefix = route.prefix();
            MacAddress nextHopMac = route.nextHopMac();
            VlanId nextHopVlan = route.nextHopVlan();
            Set<ConnectPoint> locations = srManager.nextHopLocations(route);

            locations.forEach(location -> {
                log.debug("RouteRemoved. removeSubnet {}, {}", location, prefix);
                srManager.deviceConfiguration.removeSubnet(location, prefix);
                // We don't need to call revokeRoute again since revokeSubnet will remove the prefix
                // from all devices, including the ones that next hop attaches to.

                // Also remove redirection flows on the pair device if exists.
                Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(location.deviceId());
                Optional<PortNumber> pairLocalPort = srManager.getPairLocalPorts(location.deviceId());
                if (pairDeviceId.isPresent() && pairLocalPort.isPresent()) {
                    // NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
                    //       when the host is untagged
                    VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(location)).orElse(nextHopVlan);

                    log.debug("RouteRemoved. revokeRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
                    srManager.defaultRoutingHandler.revokeRoute(pairDeviceId.get(), prefix,
                            nextHopMac, vlanId, pairLocalPort.get());
                }
            });
        });
    }

    void processHostMovedEvent(HostEvent event) {
        log.info("processHostMovedEvent {}", event);
        MacAddress hostMac = event.subject().mac();
        VlanId hostVlanId = event.subject().vlan();

        affectedRoutes(hostMac, hostVlanId).forEach(affectedRoute -> {
            IpPrefix prefix = affectedRoute.prefix();
            Set<HostLocation> prevLocations = event.prevSubject().locations();
            Set<HostLocation> newLocations = event.subject().locations();

            // For each old location
            Sets.difference(prevLocations, newLocations).forEach(prevLocation -> {
                // Redirect the flows to pair link if configured
                // Note: Do not continue removing any rule
                Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(prevLocation.deviceId());
                Optional<PortNumber> pairLocalPort = srManager.getPairLocalPorts(prevLocation.deviceId());
                if (pairDeviceId.isPresent() && pairLocalPort.isPresent() && newLocations.stream()
                        .anyMatch(location -> location.deviceId().equals(pairDeviceId.get()))) {
                    // NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
                    //       when the host is untagged
                    VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(prevLocation)).orElse(hostVlanId);
                    log.debug("HostMoved. populateRoute {}, {}, {}, {}", prevLocation, prefix, hostMac, vlanId);
                    srManager.defaultRoutingHandler.populateRoute(prevLocation.deviceId(), prefix,
                            hostMac, vlanId, pairLocalPort.get());
                    return;
                }

                // No pair information supplied. Remove route
                log.debug("HostMoved. revokeRoute {}, {}, {}, {}", prevLocation, prefix, hostMac, hostVlanId);
                srManager.defaultRoutingHandler.revokeRoute(prevLocation.deviceId(), prefix,
                        hostMac, hostVlanId, prevLocation.port());
            });

            // For each new location, add all new IPs.
            Sets.difference(newLocations, prevLocations).forEach(newLocation -> {
                log.debug("HostMoved. populateRoute {}, {}, {}, {}", newLocation, prefix, hostMac, hostVlanId);
                srManager.defaultRoutingHandler.populateRoute(newLocation.deviceId(), prefix,
                        hostMac, hostVlanId, newLocation.port());
            });

        });
    }

    private Set<ResolvedRoute> affectedRoutes(MacAddress mac, VlanId vlanId) {
        return srManager.routeService.getRouteTables().stream()
                .map(routeTableId -> srManager.routeService.getRoutes(routeTableId))
                .flatMap(Collection::stream)
                .map(RouteInfo::allRoutes)
                .flatMap(Collection::stream)
                .filter(resolvedRoute -> mac.equals(resolvedRoute.nextHopMac()) &&
                        vlanId.equals(resolvedRoute.nextHopVlan())).collect(Collectors.toSet());
    }

    private boolean isReady() {
        return Objects.nonNull(srManager.deviceConfiguration) &&
                Objects.nonNull(srManager.defaultRoutingHandler);
    }

    void enqueueRouteEvent(RouteEvent routeEvent) {
        log.debug("Enqueue routeEvent {}", routeEvent);
        routeEventCache.put(routeEvent.subject().prefix(), routeEvent);
    }

    void dequeueRouteEvent(RouteEvent routeEvent) {
        log.debug("Dequeue routeEvent {}", routeEvent);
        switch (routeEvent.type()) {
            case ROUTE_ADDED:
                processRouteAddedInternal(routeEvent.alternatives());
                break;
            case ROUTE_REMOVED:
                processRouteRemovedInternal(routeEvent.alternatives());
                break;
            case ROUTE_UPDATED:
            case ALTERNATIVE_ROUTES_CHANGED:
                processRouteUpdatedInternal(Sets.newHashSet(routeEvent.alternatives()),
                        Sets.newHashSet(routeEvent.prevAlternatives()));
                break;
            default:
                break;
        }
    }
}
