package io.subutai.core.hubmanager.impl.environment.state.build;


import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.StringUtils;

import io.subutai.common.command.CommandException;
import io.subutai.common.command.CommandResult;
import io.subutai.common.command.CommandStatus;
import io.subutai.common.command.CommandUtil;
import io.subutai.common.command.RequestBuilder;
import io.subutai.common.environment.Environment;
import io.subutai.common.environment.EnvironmentNotFoundException;
import io.subutai.common.environment.HubEnvironment;
import io.subutai.common.peer.EnvironmentContainerHost;
import io.subutai.common.peer.EnvironmentId;
import io.subutai.common.peer.Host;
import io.subutai.common.peer.HostNotFoundException;
import io.subutai.core.hubmanager.api.exception.HubManagerException;
import io.subutai.core.hubmanager.impl.environment.state.Context;
import io.subutai.core.hubmanager.impl.environment.state.StateHandler;
import io.subutai.hub.share.dto.ansible.AnsibleDto;
import io.subutai.hub.share.dto.environment.EnvironmentPeerDto;


public class ConfigureEnvironmentStateHandler extends StateHandler
{

    private static final String ANSIBLE_LINK = "/rest/v1/environments/%s/ansible";
    private static final String TMP_DIR = "/tmp/";

    private final CommandUtil commandUtil = new CommandUtil();


    public ConfigureEnvironmentStateHandler( Context ctx )
    {
        super( ctx, "Configure environment" );
    }


    @Override
    protected Object doHandle( EnvironmentPeerDto peerDto ) throws HubManagerException
    {

        logStart();

        AnsibleDto ansibleDto = peerDto.getAnsibleDto();

        if ( ansibleDto != null )
        {
            startConfigureation( ansibleDto, peerDto );
        }

        logEnd();

        return peerDto;
    }


    private void startConfigureation( AnsibleDto ansibleDto, EnvironmentPeerDto peerDto )
    {
        String containerId = ansibleDto.getAnsibleContainerId();
        String repoLink = ansibleDto.getRepoLink();
        String mainAnsibleScript = ansibleDto.getAnsibleRootFile();

        prepareHostsFile( containerId, ansibleDto.getGroups() );

        copyRepoUnpack( containerId, repoLink );

        String out =
                runAnsibleScript( containerId, getDirLocation( repoLink ), mainAnsibleScript, ansibleDto.getVars() );

        peerDto.getAnsibleDto().setLogs( out );
    }


    private String runAnsibleScript( final String containerId, final String dirLocation, final String mainAnsibleScript,
                                     String extraVars )
    {
        if ( extraVars == null || StringUtils.isEmpty( extraVars ) )
        {
            extraVars = "{}";
        }

        String cmd = String.format( "cd %s; ansible-playbook  %s --extra-vars %s", TMP_DIR + dirLocation, mainAnsibleScript, extraVars );
        try
        {
            return runCmd( containerId, cmd );
        }
        catch ( HostNotFoundException e )
        {
            e.printStackTrace();
            return "Failed to run Ansible scripts inside container host";
        }
        catch ( CommandException e )
        {
            e.printStackTrace();
            return "Failed to run Ansible scripts";
        }
    }


    private String getDirLocation( String repoLink )
    {
        repoLink = repoLink.replaceAll( "https://github.com/", "" );
        repoLink = repoLink.replaceAll( "/archive/", "-" );
        repoLink = repoLink.replaceAll( ".zip", "" );
        return repoLink.split( "/" )[1];
    }


    private void copyRepoUnpack( final String containerId, final String repoLink )
    {
        String cmd = String.format( "cd %s; bash /root/get_unzip.sh %s", TMP_DIR, repoLink );

        try
        {
            runCmd( containerId, cmd );
        }
        catch ( HostNotFoundException e )
        {
            e.printStackTrace();
        }
        catch ( CommandException e )
        {
            e.printStackTrace();
        }
    }


    private void prepareHostsFile( final String containerId, Set<io.subutai.hub.share.dto.ansible.Group> groups )
    {
        for ( io.subutai.hub.share.dto.ansible.Group group : groups )
        {
            try
            {
                runCmd( containerId,
                        String.format( "echo %s >> /etc/ansible/hosts", String.format( "[%s]", group.getName() ) ) );

                for ( io.subutai.hub.share.dto.ansible.Host host : group.getHosts() )
                {
                    runCmd( containerId, String.format( "echo %s >> /etc/ansible/hosts", format( host ).trim() ) );
                }
            }
            catch ( HostNotFoundException e )
            {
                e.printStackTrace();
            }
            catch ( CommandException e )
            {
                e.printStackTrace();
            }
        }
    }


    private static String format( io.subutai.hub.share.dto.ansible.Host host )
    {

        String f = "%s ansible_user=%s template=%s ansible_ssh_host=%s";

        //if template has python3, default is python2
        if ( host.getPythonPath() != null )
        {
            f += " ansible_python_interpreter=" + host.getPythonPath();
        }

        return String.format( f, host.getHostname(), host.getAnsibleUser(), host.getTemplateName(), host.getIp() );
    }


    private String runCmd( String containerId, String cmd ) throws HostNotFoundException, CommandException
    {
        CommandResult result;

        Host host = ctx.localPeer.getContainerHostById( containerId );
        RequestBuilder rb = new RequestBuilder( cmd );
        rb.withTimeout( ( int ) TimeUnit.MINUTES.toSeconds( 5 ) );
        result = commandUtil.execute( rb, host );

        CommandStatus status = result.getStatus();
        if ( status.equals( CommandStatus.SUCCEEDED ) )
        {
            return result.getStdOut();
        }
        else
        {
            return result.getStdErr();
        }
    }
}
@@ -412,279 +412,8 @@
 er;%0A
-import io.subutai.common.environment.Environment;%0Aimport io.subutai.common.environment.EnvironmentNotFoundException;%0Aimport io.subutai.common.environment.HubEnvironment;%0Aimport io.subutai.common.peer.EnvironmentContainerHost;%0Aimport io.subutai.common.peer.EnvironmentId;%0A
 impo
@@ -444,16 +444,16 @@
 r.Host;%0A
+
 import i
@@ -1089,16 +1089,54 @@
 Util();%0A
+    private long commandTimeout = 5L;%0A
 %0A%0A    pu
@@ -1501,25 +1501,24 @@
 tartConfigur
-e
 ation( ansib
@@ -1627,17 +1627,16 @@
 Configur
-e
 ation( A
@@ -1805,24 +1805,24 @@
 RepoLink();%0A
-
         Stri
@@ -1874,24 +1874,160 @@
 ootFile();%0A%0A
+        if ( ansibleDto.getCommandTimeout() != null )%0A        %7B%0A            commandTimeout = ansibleDto.getCommandTimeout();%0A        %7D%0A%0A
         prep
@@ -5583,17 +5583,30 @@
 econds( 
-5
+commandTimeout
  ) );%0A  

make request builder timeout configurable in Environment configuration state