/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
import angular from 'angular';
import {Entity, EntityFamily} from "../util/model/entity.model";
import {Issue, ISSUE_LEVEL} from '../util/model/issue.model';
import {Dsl} from "../util/model/dsl.model";
import jsYaml from "js-yaml";
import typeNotFoundIcon from "../../img/icon-not-found.svg";

const MODULE_NAME = 'brooklyn.composer.service.blueprint-service';
const TAG = 'SERVICE :: BLUEPRINT :: ';

angular.module(MODULE_NAME, [])
    .provider('blueprintService', blueprintServiceProvider);

export default MODULE_NAME;

export const RESERVED_KEYS = ['name', 'location', 'locations', 'type', 'services', 'brooklyn.config', 'brooklyn.children', 'brooklyn.enrichers', 'brooklyn.policies'];
export const DSL_ENTITY_SPEC = '$brooklyn:entitySpec';

export function blueprintServiceProvider() {
    return {
        $get: ['$log', '$q', '$sce', 'paletteApi', 'iconGenerator', 'dslService',
            function ($log, $q, $sce, paletteApi, iconGenerator, dslService) {
            return new BlueprintService($log, $q, $sce, paletteApi, iconGenerator, dslService);
        }]
    }
}

function BlueprintService($log, $q, $sce, paletteApi, iconGenerator, dslService) {
    let blueprint = new Entity();

    return {
        setFromJson: setBlueprintFromJson,
        setFromYaml: setBlueprintFromYaml,
        get: getBlueprint,
        getAsJson: getBlueprintAsJson,
        getAsYaml: getBlueprintAsYaml,
        reset: resetBlueprint,
        find: findEntity,
        findAny: findAnyEntity,
        getEntityMetadata: getEntityMetadata,
        entityHasMetadata: entityHasMetadata,
        refreshBlueprintMetadata: refreshBlueprintMetadata,
        refreshEntityMetadata: refreshEntityMetadata,
        refreshConfigConstraints: refreshConfigConstraints,
        refreshRelationships: refreshRelationships,
        refreshAllRelationships: refreshAllRelationships,
        isReservedKey: isReservedKey,
        getIssues: getIssues,
        hasIssues: hasIssues,
        populateEntityFromApi: populateEntityFromApiSuccess,
        populateLocationFromApi: populateLocationFromApiSuccess,
        addConfigKeyDefinition: addConfigKeyDefinition,
        addParameterDefinition: addParameterDefinition,
        getRelationships: getRelationships,
    };

    function setBlueprintFromJson(jsonBlueprint) {
        if (jsonBlueprint) {
            blueprint.setEntityFromJson(jsonBlueprint);
            $log.debug(TAG + 'Blueprint set from JS', blueprint);
        } else {
            resetBlueprint();
        }
    }

    function setBlueprintFromYaml(yamlBlueprint, reset = false) {
        let newBlueprint = jsYaml.safeLoad(yamlBlueprint);
        if (reset) {
            resetBlueprint();
        }
        setBlueprintFromJson(newBlueprint);
        $log.debug(TAG + 'Blueprint set from YAML', blueprint);
        // TODO refresh the blueprint now?  see comments in yaml.state.js and on refreshBlueprint
    }

    function getBlueprint() {
        return blueprint;
    }

    function getBlueprintAsJson() {
        return blueprint.getData();
    }

    function getBlueprintAsYaml() {
        try {
            let currentModel = blueprint.getData();
            return (Object.keys(currentModel).length === 0) ? '' : jsYaml.safeDump(currentModel, { lineWidth: 127 });
        } catch (err) {
            $log.error("Error converting brooklyn blueprint (rethrowing)", err);
            throw 'Could not convert the Brooklyn blueprint into YAML format';
        }
    }

    function resetBlueprint() {
        blueprint.reset();
    }

    function findEntity(id) {
        if (!id) {
            return null;
        }
        return lookup(blueprint, id);
    }


    function findAnyEntity(id) {
        if (!id) {
            return null;
        }
        return lookup(blueprint, id, true);
    }

    function getEntityMetadata(entity) {
        let metadata = new Map();
        if (entity instanceof Entity) {
            entity.metadata.forEach((value, key)=> {
                if (RESERVED_KEYS.indexOf(key) === -1) {
                    metadata.set(key, value);
                }
            });
        }
        return metadata;
    }

    function entityHasMetadata(entity) {
        return this.getEntityMetadata(entity).size > 0;
    }

    function isReservedKey(key) {
        return RESERVED_KEYS.indexOf(key) > -1;
    }

    function getIssues(entity = blueprint) {
        let issues = [];

        if (entity.hasIssues()) {
            issues = issues.concat(entity.issues.map((issue)=> {
                let newIssue = Issue.builder().message(issue.message).group(issue.group).ref(issue.ref).level(issue.level).build();
                newIssue.entity = entity;
                return newIssue;
            }));
        }

        entity.policies.forEach((policy)=> {
            issues = issues.concat(getIssues(policy));
        });

        entity.enrichers.forEach((enricher)=> {
            issues = issues.concat(getIssues(enricher));
        });

        entity.children.forEach((child)=> {
            issues = issues.concat(getIssues(child));
        });

        return issues;
    }

    function hasIssues() {
        return this.getIssues().length > 0;
    }

    function lookup(entity, id, any = false) {
        if (entity._id === id) {
            return entity;
        }
        if (entity.childrenAsMap.has(id)) {
            return entity.childrenAsMap.get(id);
        }
        if (entity.policies.has(id)) {
            return entity.policies.get(id);
        }
        if (entity.enrichers.has(id)) {
            return entity.enrichers.get(id);
        }
        let memberSpecs = Object.values(entity.getClusterMemberspecEntities()).filter((memberSpec)=>(memberSpec._id === id));
        if (memberSpecs.length === 1) {
            return memberSpecs[0];
        }
        for (let child of entity.childrenAsMap.values()) {
            let ret = lookup(child, id, any);
            if (ret !== null) {
                return ret;
            }
        }
        return null;
    }

    function refreshBlueprintMetadata(entity = blueprint, family = 'ENTITY') {
        // TODO ideally we'd have a cache for all types
        return refreshEntityMetadata(entity, family).then(()=> {
            return $q.all(entity.children.reduce((result, child) => {
                result.push(refreshBlueprintMetadata(child));
                return result;
            }, []));
        }).then(() => {
            return entity;
        });
    }

    function refreshEntityMetadata(entity, family) {
        entity.miscData.set('loading', true);
        return $q.all([refreshTypeMetadata(entity, family), refreshLocationMetadata(entity)]).then(()=> {
            entity.miscData.set('loading', false);
            return refreshRelationships(entity);
        }).then(() => {
            return $q.all([
                refreshConfigConstraints(entity),
                refreshConfigMemberspecsMetadata(entity),
                refreshPoliciesMetadata(entity),
                refreshEnrichersMetadata(entity),
            ]);
        }).then(()=> {
            return entity;
        });
    }

    function refreshTypeMetadata(entity, family) {
        let deferred = $q.defer();

        if (entity.hasType()) {
            entity.family = family.id;

            let promise = entity.miscData.has('bundle')
                ? paletteApi.getBundleType(entity.miscData.get('bundle').symbolicName, entity.miscData.get('bundle').version, entity.type, entity.version, entity.config)
                : paletteApi.getType(entity.type, entity.version, entity.config);

            promise.then((data)=> {
                deferred.resolve(populateEntityFromApiSuccess(entity, data));
            }).catch(function (error) {
                deferred.resolve(populateEntityFromApiError(entity, error));
            });
        } else if (entity.parent) {
            entity.clearIssues({group: 'type'}).addIssue(Issue.builder().group('type').message('Entity needs a type').level(ISSUE_LEVEL.WARN).build());
            entity.miscData.set('sensors', []);
            entity.miscData.set('traits', []);
            deferred.resolve(entity);
            addUnlistedConfigKeysDefinitions(entity);
            addUnlistedParameterDefinitions(entity);
        } else {
            entity.miscData.set('sensors', []);
            entity.miscData.set('traits', []);
            deferred.resolve(entity);
            addUnlistedConfigKeysDefinitions(entity);
            addUnlistedParameterDefinitions(entity);
        }

        return deferred.promise;
    }

    function locationType(location) {
        if (!location || typeof location === 'string') return location;
        if (typeof location === 'object' && Object.keys(location).length==1) return Object.keys(location)[0];
        return null;
    }
    
    function refreshLocationMetadata(entity) {
        let deferred = $q.defer();

        if (entity.hasLocation()) {
            let type = locationType(entity.location);
            if (type && type.startsWith) {
                if (type.startsWith("jclouds:")) {
                    // types eg jclouds:aws-ec2 are low-level, not in the catalog
                    deferred.resolve(populateLocationFromApiSuccess(entity, { yamlHere: entity.location }));
                } else {
                    paletteApi.getLocation(locationType(entity.location)).then((location) => {
                        let loc = Object.assign({}, location.catalog || location, {yamlHere: entity.location});
                        deferred.resolve(populateLocationFromApiSuccess(entity, loc));
                    }).catch(function () {
                        deferred.resolve(populateLocationFromApiError(entity));
                    });
                }
            } else {
                deferred.resolve(entity);
            }
        } else {
            deferred.resolve(entity);
        }

        return deferred.promise;
    }

    function refreshConfigConstraints(entity) {
        return $q((resolve) => {
            if (entity.miscData.has('config')) {
                entity.miscData.get('config')
                    .filter(config => config.constraints && config.constraints.length > 0)
                    .forEach(config => {
                        for (let constraintO of config.constraints) {
                            let message = null;
                            let key = null, args = null;
                            if (constraintO instanceof String || typeof constraintO=='string') {
                                key = constraintO;
                            } else if (Object.keys(constraintO).length==1) {
                                key = Object.keys(constraintO)[0];
                                args = constraintO[key];
                            } else {
                                $log.warn("Unknown constraint object", typeof constraintO, constraintO, config);
                                key = constraintO;
                            }
                            let val = (k) => entity.config.get(k || config.name);
                            let isSet = (k) => entity.config.has(k || config.name) && angular.isDefined(val(k));
                            let isAnySet = (k) => {
                                if (!k || !Array.isArray(k)) return false;
                                return k.some(isSet);
                            }
                            let hasDefault = () => angular.isDefined(config.defaultValue);
                            switch (key) {
                                case 'Predicates.notNull()':
                                case 'Predicates.notNull':
                                    if (!isSet() && !hasDefault()) {
                                        message = `<samp>${config.name}</samp> is required`;
                                    }
                                    break;
                                case 'required':
                                    if (!isSet() && !hasDefault() && val()!='') {
                                        message = `<samp>${config.name}</samp> is required`;
                                    }
                                    break;
                                case 'regex':
                                    if (isSet() && !(new RegExp(args).test(val))) {
                                        message = `<samp>${config.name}</samp> does not match the required format: <samp>${args}</samp>`;
                                    }
                                    break;
                                case 'forbiddenIf':
                                    if (isSet() && isSet(args)) {
                                        message = `<samp>${config.name}</samp> and <samp>${args}</samp> cannot both be set`;
                                    }
                                    break;
                                case 'forbiddenUnless':
                                    if (isSet() && !isSet(args)) {
                                        message = `<samp>${config.name}</samp> can only be set when <samp>${args}</samp> is set`;
                                    }
                                    break;
                                case 'requiredIf':
                                    if (!isSet() && isSet(args)) {
                                        message = `<samp>${config.name}</samp> must be set if <samp>${args}</samp> is set`;
                                    }
                                    break;
                                case 'requiredUnless':
                                    if (!isSet() && !isSet(args)) {
                                        message = `<samp>${config.name}</samp> or <samp>${args}</samp> is required`;
                                    }
                                    break;
                                case 'requiredUnlessAnyOf':
                                    if (!isSet() && !isAnySet(args)) {
                                        message = `<samp>${config.name}</samp> or one of <samp>${args}</samp> is required`;
                                    }
                                    break;
                                case 'forbiddenUnlessAnyOf':
                                    if (isSet() && !isAnySet(args)) {
                                        message = `<samp>${config.name}</samp> cannot be set if any of <samp>${args}</samp> are set`;
                                    }
                                    break;
                                default:
                                    $log.warn("Unknown constraint predicate", constraintO, config);
                            }
                            if (message !== null) {
                                entity.addIssue(Issue.builder().group('config').ref(config.name).message($sce.trustAsHtml(message)).build());
                            }
                        }
                    });
            }
            resolve();
        });
    }

    function refreshConfigMemberspecsMetadata(entity) {
        let promiseArray = [];
        Object.values(entity.getClusterMemberspecEntities()).forEach((memberSpec)=> {
            // memberSpec can be `undefined` if the member spec is not a `$brooklyn:entitySpec`, e.g. it is `$brooklyn:config("spec")`.
            // there may be a better way but this seems to handle it.
            if (memberSpec) promiseArray.push(refreshBlueprintMetadata(memberSpec, 'SPEC'));
        });
        return $q.all(promiseArray);
    }

    function refreshPoliciesMetadata(entity) {
        return $q.all(entity.getPoliciesAsArray().reduce((result, policy)=> {
            policy.miscData.set('loading', true);
            policy.family = 'POLICY';

            let deferred = $q.defer();

            paletteApi.getType(policy.type, policy.version).then((data)=> {
                deferred.resolve(populateEntityFromApiSuccess(policy, data));
            }).catch(function (error) {
                deferred.resolve(populateEntityFromApiError(policy, error));
            }).finally(()=> {
                policy.miscData.set('loading', false);
            });
            result.push(deferred);
            return result;
        }, []));
    }

    function refreshEnrichersMetadata(entity) {
        return $q.all(entity.getEnrichersAsArray().reduce((result, enricher)=> {
            enricher.miscData.set('loading', true);
            enricher.family = 'ENRICHER';

            let deferred = $q.defer();

            paletteApi.getType(enricher.type, enricher.version).then((data)=> {
                deferred.resolve(populateEntityFromApiSuccess(enricher, data));
            }).catch(function (error) {
                deferred.resolve(populateEntityFromApiError(enricher, error));
            }).finally(()=> {
                enricher.miscData.set('loading', false);
            });
            result.push(deferred);
            return result;
        }, []));
    }

    function parseInput(input, entity) {
        return $q((resolve, reject) => {
            try {
                let parsed = dslService.parse(input, entity, getBlueprint());
                if (parsed.kind && parsed.kind.family === 'constant') {
                    reject('constants not interpreted as DSL when parsed', input);
                } else {
                    resolve(parsed);
                }
            } catch (ex) {
                $log.debug(ex);
                reject(ex, input);
            }
        });
    }

    function refreshRelationships(entity) {
        return $q.all(Array.from(entity.config.keys()).reduce((promises, key) => {
            let value = entity.config.get(key);

            // Return promises that returns an object like { key: "my-config-key-key", issues: [] }
            if (value instanceof Dsl) {
                promises.push(
                    parseInput(value.toString(), entity).then(dsl => {
                        entity.config.set(key, dsl);
                        return {
                            key: key,
                            issues: dsl.getAllIssues()
                        };
                    }).catch(() => $q.resolve({
                        key: key,
                        issues: []
                    }))
                );
            } else if (value instanceof Array) {
                promises.push(
                    $q.all(value.reduce((issues, itemValue, itemIndex) => {
                        return issues.concat(
                            parseInput(itemValue, entity).then(dsl => {
                                value[itemIndex] = dsl;
                                return dsl.getAllIssues();
                            }).catch(() => [])
                        );
                    }, [])).then(issues => {
                        return {
                            key: key,
                            issues: issues.reduce((acc, issue) => acc.concat(issue), [])
                        }
                    })
                );
            } else if (value instanceof Object) {
                promises.push(
                    $q.all(Object.keys(value).reduce((issues, itemKey) => {
                        return issues.concat(
                            parseInput(value[itemKey], entity).then(dsl => {
                                value[itemKey] = dsl;
                                return dsl.getAllIssues();
                            }).catch(() => [])
                        );
                    }, [])).then(issues => {
                        return {
                            key: key,
                            issues: issues.reduce((acc, issue) => acc.concat(issue), [])
                        }
                    })
                );
            } else {
                promises.push(
                    parseInput(value, entity).then(dsl => {
                        entity.config.set(key, dsl);
                        return {
                            key: key,
                            issues: dsl.getAllIssues()
                        };
                    }).catch(() => $q.resolve({
                        key: key,
                        issues: []
                    }))
                );
            }

            return promises;
        }, [])).then(results => {
            results.forEach(result => {
                entity.clearIssues({ref: result.key});
                result.issues.forEach(issue => {
                    entity.addIssue(Issue.builder().group('config').ref(result.key).message($sce.trustAsHtml(issue)).build());
                });
            })
        });
    }

    function refreshAllRelationships(entity = blueprint) {
        let promises = [];
        promises.push(refreshRelationships(entity));
        promises.concat(entity.children.map(child => refreshAllRelationships(child)));

        return $q.all(promises);
    }

    function addConfigKeyDefinition(config, key) {
        config.push({
            "name": key,
            "label": key,
            "description": "",
            "priority": 1,
            "pinned": true,
            "type": "java.lang.String",
            "constraints": [],
        });
    }

    function addParameterDefinition(params, key) {
        params.push({
            "name": key,
            "type": "string",
        });
    }

    function addUnlistedConfigKeysDefinitions(entity) {
        // copy config key definitions set on this entity into the miscData aggregated view
        let allConfig = entity.miscData.get('config') || [];
        entity.config.forEach((value, key) => {
            if (!allConfig.some((e) => e.name === key)) {
                addConfigKeyDefinition(allConfig, key);
            }
        });
        entity.miscData.set('config', allConfig);
    }

    function addUnlistedParameterDefinitions(entity) {
        // copy parameter definitions set on this entity into the miscData aggregated view;
        // TODO see discussions in PR 112 about whether this is necessary and/or there is a better way
        let allParams = entity.miscData.get('parameters') || [];
        entity.parameters.forEach((param) => {
            if (!allParams.some((e) => e.name === param.name)) {
                allParams.push(param);
            }
        });
        entity.miscData.set('parameters', allParams);
    }

    function populateEntityFromApiSuccess(entity, data) {
        entity.clearIssues({group: 'type'});
        entity.type = data.symbolicName;
        entity.icon = data.iconUrl || iconGenerator(data.symbolicName);
        entity.miscData.set('important', !!data.iconUrl);
        entity.miscData.set('bundle', {
            symbolicName: data.containingBundle.split(':')[0],
            version: data.containingBundle.split(':')[1]
        });
        entity.miscData.set('typeName', data.displayName || data.symbolicName);
        entity.miscData.set('displayName', data.displayName);
        entity.miscData.set('symbolicName', data.symbolicName);
        entity.miscData.set('description', data.description);
        entity.miscData.set('config', data.config || []);
        entity.miscData.set('parameters', data.parameters || []);
        entity.miscData.set('sensors', data.sensors || []);
        entity.miscData.set('traits', data.supertypes || []);
        entity.miscData.set('tags', data.tags || []);
        var uiHints = {};
        data.tags.forEach( (t) => { 
            mergeAppendingLists(uiHints, t['ui-composer-hints']);
        });
        entity.miscData.set('ui-composer-hints', uiHints);
        entity.miscData.set('virtual', data.virtual || null);
        addUnlistedConfigKeysDefinitions(entity);
        addUnlistedParameterDefinitions(entity);
        return entity;
    }
    function mergeAppendingLists(dst, src) {
        for (let p in src) {
            if (Array.isArray(dst[p]) || Array.isArray(src[p])) {
                dst[p] = [].concat(dst[p] || [], src[p]);
            } else {
                dst[p] = Object.assign({}, dst[p], src[p]);
            }
        }
        return dst;
    }

    function populateEntityFromApiError(entity, error) {
        $log.warn("Error loading/populating type, data will be incomplete.", entity, error);
        entity.clearIssues({group: 'type'});
        entity.addIssue(Issue.builder().group('type').message($sce.trustAsHtml(`Type <samp>${entity.type + (entity.hasVersion ? ':' + entity.version : '')}</samp> does not exist`)).build());
        entity.miscData.set('typeName', entity.type || '');
        entity.miscData.set('config', []);
        entity.miscData.set('parameters', []);
        entity.miscData.set('sensors', []);
        entity.miscData.set('traits', []);
        entity.miscData.set('virtual', null);
        entity.icon = typeNotFoundIcon;
        addUnlistedConfigKeysDefinitions(entity);
        addUnlistedParameterDefinitions(entity);
        return entity;
    }

    function populateLocationFromApiCommon(entity, data) {
        entity.clearIssues({group: 'location'});
        entity.location = data.yamlHere || data.symbolicName;
        
        let name = data.name || data.displayName;
        if (!name && data.yamlHere) {
            name = typeof data.yamlHere === 'object' ? Object.keys(data.yamlHere)[0] : data.yamlHere;
        }
        if (!name) name =  data.symbolicName;
        entity.miscData.set('locationName', name);
        
        // use icon on item, but if none then generate using *yaml* to distinguish when someone has changed it
        // (especially for things like jclouds:aws-ec2 -- the config is more interesting than the type name)
        entity.miscData.set('locationIcon', data==null ? null : data.iconUrl || iconGenerator(data.yamlHere ? JSON.stringify(data.yamlHere) : data.symbolicName));
        return entity;
    }
    
    function populateLocationFromApiSuccess(entity, data) {
        populateLocationFromApiCommon(entity, data);
    }

    function populateLocationFromApiError(entity) {
        populateLocationFromApiCommon(entity, { yamlHere: entity.location });
        entity.addIssue(Issue.builder().level(ISSUE_LEVEL.WARN).group('location').message($sce.trustAsHtml(`Location <samp>${!(entity.location instanceof String) ? JSON.stringify(entity.location) : entity.location}</samp> does not exist in your local catalog. Deployment might fail.`)).build());
        entity.miscData.set('locationIcon', typeNotFoundIcon);
        return entity;
    }

    /**
     * Retrieves all the Entities referenced by an Entity
     * @param {Entity} entity the Entity to resolve relative references from
     * @return {Array} of objects that contains source and target entities
     */
    function getRelationships(entity = blueprint) {
        let set = Array.from(entity.config.values())
            .reduce((set, config)=> {
                if (config instanceof Dsl) {
                    config.relationships.forEach((entity) => {
                        if (entity !== null) {
                            set.add(entity);
                        }
                    });
                }
                if (config instanceof Array) {
                    config
                        .filter(conf => conf instanceof Dsl)
                        .reduce((set, config)=> {
                            config.relationships.forEach((entity)=> {
                                if (entity !== null) {
                                    set.add(entity);
                                }
                            });
                            return set;
                        }, set);
                }
                if (config instanceof Object) {
                    Object.keys(config)
                        .filter(key => config[key] instanceof Dsl)
                        .reduce((set, key)=> {
                            config[key].relationships.forEach((entity)=> {
                                if (entity !== null) {
                                    set.add(entity);
                                }
                            });
                            return set;
                        }, set);
                }
                return set;
            }, new Set());

        let relationships = Array.from(set).map((relation) => {
            return {
                source: entity,
                target: relation
            };
        });

        relationships = Array.from(entity.config.values())
            .filter(config => config && config[DSL_ENTITY_SPEC] && config[DSL_ENTITY_SPEC] instanceof Entity)
            .map(config => config[DSL_ENTITY_SPEC])
            .reduce((relationships, spec) => {
            return relationships.concat(getRelationships(spec));
        }, relationships);

        return entity.children.reduce((relationships, child) => {
            return relationships.concat(getRelationships(child))
        }, relationships);
    }

}
