/////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2020-     Equinor ASA
//
//  ResInsight is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
//  WARRANTY; without even the implied warranty of MERCHANTABILITY or
//  FITNESS FOR A PARTICULAR PURPOSE.
//
//  See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
//  for more details.
//
/////////////////////////////////////////////////////////////////////////////////

#include "RicNewWellPathLateralAtDepthFeature.h"

#include "WellPathCommands/RicWellPathsUnitSystemSettingsImpl.h"

#include "RigWellPath.h"
#include "RimFishbones.h"
#include "RimFishbonesCollection.h"
#include "RimModeledWellPath.h"
#include "RimProject.h"
#include "RimTools.h"
#include "RimWellPath.h"
#include "RimWellPathCollection.h"
#include "RimWellPathGeometryDef.h"
#include "RimWellPathTarget.h"

#include "Riu3DMainWindowTools.h"
#include "Riu3dSelectionManager.h"

#include "cafSelectionManager.h"

#include <QAction>

#include "RiaTextStringTools.h"
#include <cmath>

CAF_CMD_SOURCE_INIT( RicNewWellPathLateralAtDepthFeature, "RicNewWellPathLateralAtDepthFeature" );

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicNewWellPathLateralAtDepthFeature::isCommandEnabled()
{
    if ( RiuWellPathSelectionItem::wellPathSelectionItem() )
    {
        return true;
    }

    return false;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewWellPathLateralAtDepthFeature::onActionTriggered( bool isChecked )
{
    RiuWellPathSelectionItem* wellPathSelItem = RiuWellPathSelectionItem::wellPathSelectionItem();
    CVF_ASSERT( wellPathSelItem );

    RimWellPath* parentWellPath = wellPathSelItem->m_wellpath;
    CVF_ASSERT( parentWellPath );

    double parentWellMD = wellPathSelItem->m_measuredDepth;

    createLateralAtMeasuredDepth( parentWellPath, parentWellMD );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewWellPathLateralAtDepthFeature::setupActionLook( QAction* actionToSetup )
{
    actionToSetup->setText( "Create Well Path Lateral at this Depth" );
    actionToSetup->setIcon( QIcon( ":/Well.svg" ) );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimModeledWellPath* RicNewWellPathLateralAtDepthFeature::createLateralAtMeasuredDepth( RimWellPath* parentWellPath, double parentWellMD )
{
    RimProject*            project      = RimProject::current();
    RimWellPathCollection* wellPathColl = RimTools::wellPathCollection();
    if ( project && wellPathColl )
    {
        auto newModeledWellPath = new RimModeledWellPath();
        newModeledWellPath->geometryDefinition()->enableReferencePointFromTopLevelWell( true );

        if ( parentWellPath->wellPathGeometry() && parentWellPath->wellPathGeometry()->measuredDepths().size() > 2 )
        {
            auto [pointVector, measuredDepths] =
                parentWellPath->wellPathGeometry()->clippedPointSubset( parentWellPath->wellPathGeometry()->measuredDepths().front(),
                                                                        parentWellMD );

            newModeledWellPath->geometryDefinition()->setMdAtFirstTarget( measuredDepths.back() );
            newModeledWellPath->geometryDefinition()->setFixedWellPathPoints( pointVector );
            newModeledWellPath->geometryDefinition()->setFixedMeasuredDepths( measuredDepths );
        }

        newModeledWellPath->geometryDefinition()->setIsAttachedToParentWell( true );
        newModeledWellPath->geometryDefinition()->setUseAutoGeneratedTargetAtSeaLevel( false );

        auto nameOfNewWell = updateNameOfParentAndFindNameOfSideStep( parentWellPath );
        newModeledWellPath->setName( nameOfNewWell );
        newModeledWellPath->connectWellPaths( parentWellPath, parentWellMD );

        newModeledWellPath->geometryDefinition()->enableTargetPointPicking( true );
        newModeledWellPath->setUnitSystem( parentWellPath->unitSystem() );

        newModeledWellPath->createWellPathGeometry();

        wellPathColl->addWellPath( newModeledWellPath );
        wellPathColl->updateAllRequiredEditors();

        project->scheduleCreateDisplayModelAndRedrawAllViews();

        Riu3DMainWindowTools::selectAsCurrentItem( newModeledWellPath->geometryDefinition() );

        return newModeledWellPath;
    }

    return nullptr;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicNewWellPathLateralAtDepthFeature::updateNameOfParentAndFindNameOfSideStep( RimWellPath* parentWellPath )
{
    if ( !parentWellPath ) return "";

    QString nameOfNewWell;

    auto topLevelWell = parentWellPath->topLevelWellPath();

    QStringList allNames;
    {
        RimProject*                      proj      = RimProject::current();
        const std::vector<RimWellPath*>& wellPaths = proj->allWellPaths();

        for ( auto wellPath : wellPaths )
        {
            if ( wellPath )
            {
                auto currentTopLevelWell = wellPath->topLevelWellPath();
                if ( topLevelWell == currentTopLevelWell )
                {
                    allNames.push_back( wellPath->name() );
                }
            }
        }
    }

    if ( allNames.size() == 1 )
    {
        QString name = parentWellPath->name();

        if ( name.contains( "Y1" ) )
        {
            nameOfNewWell = name.replace( "Y1", "Y2" );
        }
        else
        {
            parentWellPath->setNameNoUpdateOfExportName( name + " Y1" );
            nameOfNewWell = name + " Y2";
        }

        return nameOfNewWell;
    }

    {
        QString commonRoot = RiaTextStringTools::commonRoot( allNames );

        int maxYValue = 0;
        for ( auto n : allNames )
        {
            auto suffix = n.replace( commonRoot, "" );

            int candidate = suffix.toInt();
            maxYValue     = std::max( maxYValue, candidate );
        }

        nameOfNewWell = QString( "%1%2" ).arg( commonRoot ).arg( maxYValue + 1 );
    }

    return nameOfNewWell;
}
