/*-
 * ~~~~~~licensing~~~~~~
 * profile-manager
 * ==========
 * Copyright (C) 2020 - 2025 EmDev LLC
 * ==========
 * You may not use this file except in accordance with the License Terms of the Copyright
 * Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
 * rights to the Software and any copies are the property of the Copyright Holder. Unless
 * it is explicitly allowed the Copyright Holder, the User is prohibited from using the
 * Software for commercial purposes to provide services to third parties.
 * 
 * The Copyright Holder hereby declares that the Software is provided on an "AS IS".
 * Under no circumstances does the Copyright Holder guarantee or promise that the
 * Software provided by him will be suitable or not suitable for the specific purposes
 * of the User, that the Software will meet all commercial and personal subjective
 * expectations of the User, that the Software will work properly, without technical
 * errors, quickly and uninterruptedly.
 * 
 * Under no circumstances shall the Copyright Holder or its Affiliates is not liable
 * to the User for any direct or indirect losses of the User, his expenses or actual
 * damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
 * or damage to data, property, etc.
 * ~~~~~~/licensing~~~~~~
 */
package ru.entaxy.esb.system.management.profile.manager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import ru.entaxy.esb.system.connector.entity.Connector;
import ru.entaxy.esb.system.jpa.SystemService;
import ru.entaxy.esb.system.jpa.entity.ExportAllowed;
import ru.entaxy.esb.system.jpa.entity.System;
import ru.entaxy.esb.system.management.bridge.profile.manager.BridgeProfileManager;
import ru.entaxy.esb.system.management.bridge.profile.manager.dto.BridgeProfileDto;
import ru.entaxy.esb.system.management.bundle.jpa.dto.BundleDto;
import ru.entaxy.esb.system.management.bundle.manager.BundleManager;
import ru.entaxy.esb.system.management.connector.manager.ConnectorManager;
import ru.entaxy.esb.system.management.permission.manager.PermissionManager;
import ru.entaxy.esb.system.management.profile.manager.dto.ProfileDto;
import ru.entaxy.esb.system.management.profile.manager.mapper.ProfileMapper;
import ru.entaxy.esb.system.management.route.manager.RouteManager;

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

public class ProfileManagerImpl implements ProfileManager {
	
	private static final Log LOG = LogFactory.getLog(ProfileManagerImpl.class);
	
	private static final String PROFILE = "profile";

	private boolean isRestoreFromDB;
	private BundleManager bundleManager;

	private SystemService systemService;
	private ProfileMapper profileMapper;

	private BridgeProfileManager bridgeProfileManager;
	private ConnectorManager connectorManager;
	private PermissionManager permissionManager;
	private RouteManager routeManager;

	@Override
	public BundleDto installProfile(ProfileDto profileDto) throws Exception {
		BundleDto bundle;
		System system = null;
		try {
			system = systemService.create(profileMapper.toSystemEntity(profileDto));
			bundle = bundleManager.installAndStartBundle(system.getName(), PROFILE,
					String.valueOf(system.getVersion()));
			systemService.setBundleEntity(system, profileMapper.toBundleEntity(bundle));
			routeManager.createDefaultRoute(profileDto.getName());
		} catch (Exception ex) {
			systemService.remove(system);
			throw ex;
		}
		return bundle;
	}

	@Override
	public BundleDto startProfile(ProfileDto profileDto) throws Exception {
		System system = systemService.getByUuid(profileDto.getUuid());
		BundleDto bundle = bundleManager.startBundle(profileMapper.toBundleDto(system.getBundleEntity()));
		systemService.setBundleEntity(system, profileMapper.toBundleEntity(bundle));
		return bundle;
	}

	@Override
	public BundleDto stopProfile(ProfileDto profileDto) throws Exception {
		System system = systemService.getByUuid(profileDto.getUuid());
		stopProfileDependency(system);
		BundleDto bundle = bundleManager.stopBundle(profileMapper.toBundleDto(system.getBundleEntity()));
		systemService.setBundleEntity(system, profileMapper.toBundleEntity(bundle));
		return bundle;
	}

	@Override
	public void uninstallProfile(ProfileDto profileDto) throws Exception {
		System system = systemService.getByUuid(profileDto.getUuid());
		uninstallProfileDependency(system);
		bundleManager.uninstallBundle(system.getName(), PROFILE, String.valueOf(system.getVersion()));
		systemService.remove(system.getId());
	}

	@Override
	public ProfileDto getProfile(ProfileDto profileDto) throws Exception {
		return profileMapper.toProfileDto(systemService.getByUuid(profileDto.getUuid()));
	}

	@Override
	public List<ProfileDto> getProfiles() throws Exception {
		return profileMapper.toListProfiles(systemService.getFullSystemListByOriginIsEmpty());
	}

	@Override
	public List<ProfileDto> getPermissionsBySubject(String uuid) throws Exception {
		return profileMapper.toListProfiles(systemService.getFullSystemListByPermissionBySubject(uuid));
	}

	@Override
	public List<ProfileDto> getPermissionsByObject(String uuid) throws Exception {
		return profileMapper.toListProfiles(systemService.getFullSystemListByPermissionByObject(uuid));
	}

	@Override
	public void restore() throws Exception {
		if (!isRestoreFromDB)
			return;
		for (System system : systemService.getSystemList()) {
			if  (system.getOrigin() == null || system.getOrigin().isEmpty())  {
				try {
					LOG.info("Restore profile of system " + system.getName());
					bundleManager.restore(profileMapper.toBundleDto(system.getBundleEntity()));
				} catch (IOException e) {
					LOG.warn("Recreate profile of system " + system.getName());
					restoreProfile(system);
				}
				try {
					if(system.getDefaultRoute())
						routeManager.createDefaultRoute(system.getName());
				} catch (Exception e) {
					LOG.warn("Error from create default route " + system.getName());
					throw e;
				}
			}
		}
	}

	private void restoreProfile(System system) throws Exception {
		BundleDto bundle = bundleManager.installBundle(system.getName(), PROFILE,
				String.valueOf(system.getVersion()));
		
		bundle.setStatus(profileMapper.toBundleDto(system.getBundleEntity()).getStatus());
		
		bundleManager.checkCurrentBundleStatus(bundle);
		
		systemService.setBundleEntity(system, profileMapper.toBundleEntity(bundle));
	}

	private void stopProfileDependency(System system) throws Exception {
		if (system.getConnectors() != null) {
			for (Connector connector : system.getConnectors()) {
				connectorManager.stopConnector(connector);
			}
		}
		BridgeProfileDto bridgeProfileDto = profileMapper.toBridgeProfileDto(system);
		for (ExportAllowed exportAllowed : system.getExportAllowed()) {
			bridgeProfileDto.setEsbName(exportAllowed.getName());
			bridgeProfileManager.stopBridgeProfile(bridgeProfileDto);
		}
	}

	private void uninstallProfileDependency(System system) throws Exception {
		if (system.getConnectors() != null) {
			for (Connector connector : system.getConnectors()) {
				connectorManager.uninstallConnector(connector);
			}
		}
		BridgeProfileDto bridgeProfileDto = profileMapper.toBridgeProfileDto(system);
		for (ExportAllowed exportAllowed : system.getExportAllowed()) {
			bridgeProfileDto.setEsbName(exportAllowed.getName());
			bridgeProfileManager.uninstallBridgeProfile(bridgeProfileDto);
		}
		permissionManager.removeAllPermission(system.getId());
		routeManager.uninstallDefaultRoute(system.getName());
		routeManager.uninstallDefaultRoute(system.getName() + "-default-route"); // fixme temporary solution
	}

	public void setProfileMapper(ProfileMapper profileMapper) {
		this.profileMapper = profileMapper;
	}

	public void setBundleManager(BundleManager bundleManager) {
		this.bundleManager = bundleManager;
	}

	public void setSystemService(SystemService systemService) {
		this.systemService = systemService;
	}

	public void setBridgeProfileManager(BridgeProfileManager bridgeProfileManager) {
		this.bridgeProfileManager = bridgeProfileManager;
	}

	public void setRouteManager(RouteManager routeManager) {
		this.routeManager = routeManager;
	}

	public void setConnectorManager(ConnectorManager connectorManager) {
		this.connectorManager = connectorManager;
	}

	public void setPermissionManager(PermissionManager permissionManager) {
		this.permissionManager = permissionManager;
	}

	public void setIsRestoreFromDB(String isRestoreFromDB) {
		this.isRestoreFromDB = Boolean.parseBoolean(isRestoreFromDB);
	}
}
