package ru.bitel.bgbilling.modules.tv.dyn.lfstrm;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONObject;

import ru.bitel.bgbilling.kernel.container.managed.ServerContext;
import ru.bitel.bgbilling.kernel.module.common.bean.User;
import ru.bitel.bgbilling.modules.tv.common.bean.TvAccount;
import ru.bitel.bgbilling.modules.tv.server.bean.TvAccountDao;
import ru.bitel.bgbilling.modules.tv.server.handler.HttpHandler;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.Utils;
import ru.bitel.oss.systems.inventory.product.common.bean.Product;
import ru.bitel.oss.systems.inventory.product.common.bean.ProductSpec;
import ru.bitel.oss.systems.inventory.product.server.bean.ProductDao;
import ru.bitel.oss.systems.inventory.product.server.bean.ProductSpecDao;

public class LifeStreamHandler
    implements HttpHandler
{
    private static final Logger logger = LogManager.getLogger();

    @Override
    public void handle( int moduleId, HttpServletRequest request, HttpServletResponse response )
    {
        ServerContext context = new ServerContext( Setup.getSetup(), moduleId, 0 );

        try
        {
            request.setCharacterEncoding( "UTF-8" );
            response.setCharacterEncoding( "UTF-8" );

            JSONObject upsaleRequestV2 = parseUpsaleRequestV2( request );
            
            // ищем клиента
            TvAccount tvAccount = null;
            try(TvAccountDao tvAccountDao = new TvAccountDao( context.getConnection(), context.getModuleId() ) )
            {
                tvAccount = tvAccountDao.getByIdentifier( upsaleRequestV2.optString( "id" ), LocalDate.now() );
                if ( tvAccount == null )
                {
                    sendErrorResponse400( response, "error_no_account", "id = " + upsaleRequestV2.optString( "id" ), "" );
                    return;
                }
            }
            
            // ищем продукт
            ProductSpec productSpec = null;
            try ( ProductDao productDao = new ProductDao( context.getConnection(), User.USER_SERVER );
                  ProductSpecDao productSpecDao = new ProductSpecDao( context.getConnection() ); )
            {
                // продукт который хотят подключить
                productSpec = productSpecDao.getByIdentifier( upsaleRequestV2.optString( "offerId" ) );
                if ( productSpec == null )
                {
                    sendErrorResponse400( response, "error_bad_request", "Продукт с Identifier = " + upsaleRequestV2.optString( "offerId" ) + "[#offerId] не найдена", "" );
                    return;
                }
                
                // проверка не подключен ли он уже у клиента
                // получаем список текущих услуг на аккаунте
                List<Product> productList = productDao.list( moduleId, tvAccount.getContractId(), tvAccount.getId(), false, new Date() );
                for ( Product product : productList )
                {
                    if ( product.getProductSpecId() == productSpec.getId() )
                    {
                        sendRequestProcessedResponse( response, "no_action_required", null, 0, 0 );
                        return;
                    }
                }
            }
        }
        catch( Exception ex )
        {
            logger.error( ex.getMessage(), ex );
            
            sendErrorResponse500( response, "exception", ex.getLocalizedMessage(), ex.toString() );
        }
    }
    
    private JSONObject parseUpsaleRequestV2( HttpServletRequest request )
        throws Exception
    {
        return new JSONObject( new String( Utils.readByBlock( request.getInputStream() ), "UTF-8" ) );
    }
    
    /**
     * Результат выполнения запроса. Может принимать одно из следующих значений:
     *   subscription_added - подключена дополнительная подписка, детали в поле transaction
     *   subscription_changed - изменена базовая подписка, детали в поле transaction
     *   no_action_required - подписка уже существует и активна
     *   no_sufficient_balance - недостаточно средств для подключения, сумма для пополнения в поле refillAmount
     *   no_subscription_rules - подключение подписки противоречит внутренним правилам биллинга
     * @param response
     * @param id
     */
    private void sendRequestProcessedResponse( HttpServletResponse response, String id, String transactionId, long transactionTimestamt, int refillAmount )
    {
        JSONObject responseJson = new JSONObject();
        responseJson.put( "id", id );
        if ( transactionId != null )
        {
            JSONObject transaction = new JSONObject();
            transaction.put( "id", transactionId );
            transaction.put( "timestamp", transactionTimestamt );
            responseJson.put( "transaction", transaction );
        }
        if ( refillAmount > 0 )
        {
            responseJson.put( "refillAmount", refillAmount );
        }
        
        response.setContentType( "application/json" );
        try( Writer writer = new OutputStreamWriter( response.getOutputStream(), "UTF-8" ) )
        {
            writer.write( responseJson.toString() );
            writer.flush();
        }
        catch( IOException ex )
        {
            logger.error( ex );
        }
    }
    
    /**
     * В поле id объекта errorResponse должен быть один из следующих идентификаторов:
     *   error_no_account - абонента нет в биллинге оператора
     *   error_failed_activation - не удалось активировать услугу на TV-платформе, в поле message должно быть значение из поля error ответа от TV платформы
     *   error_bad_request - ошибка в формате запроса или содержании его полей
     * @param id
     * @return
     */
    private void sendErrorResponse400( HttpServletResponse response, String id, String message, String details )
    {
        try
        {
            response.setContentType( "application/json" );
            response.sendError( HttpServletResponse.SC_BAD_REQUEST, getErrorResponse( id, message, details ) );
        }
        catch( IOException ex )
        {
            logger.error( ex );
        }
    }

    private void sendErrorResponse500( HttpServletResponse response, String id, String message, String details )
    {
        try
        {
            response.setContentType( "application/json" );
            response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, getErrorResponse( id, message, details ) );
        }
        catch( IOException ex )
        {
            logger.error( ex );
        }
    }
    
    private String getErrorResponse( String id, String message, String details )
    {
        JSONObject errorJson = new JSONObject();
        errorJson.put( "id", id );
        errorJson.put( "message", message );
        errorJson.put( "details", details );
        return errorJson.toString();
    }
}
