package com.capgemini.reports;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.exceptions.InvalidConfigurationException;
import com.capgemini.framework.teamcenter.exceptions.NoTeamcenterConnectionException;
import com.capgemini.framework.teamcenter.policies.PolicyLocation;
import com.capgemini.reports.teamcenter.Platform;
import com.teamcenter.schemas.soa._2006_03.exceptions.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.junit.AfterClass;

/**
 * Helper class to initialize a Teamcenter connection. <br>
 * Provides daughter classes a transparent way to access a Teamcenter connection.<br>
 * The session will have its Property Policies set to the default testing policies found in "/src/test/resources/test_policy.xml".
 * <p>
 * Access the connection through the static {@link AbstractTeamcenterTest#getSession()} method.
 */
@Slf4j
public abstract class AbstractTeamcenterTest {

    /**
     * Minimum delay between each login (by milliseconds).
     **/
    private static final long LOGIN_DELAY = 30000;

    /**
     * Time by milliseconds of the last login.
     **/
    private static long lastLogInTimeMs = 0L;

    /**
     * Plateform A36 for Tests.
     */
    public static final Platform A36_URL = Platform.PF36;
    /**
     * Plateform AIX for Tests.
     */
    public static final Platform AIX_URL = Platform.AIX;
    /**
     * Plateform MIG.
     */
    public static final Platform MIG_URL = Platform.MIG;

    /**
     * The file location of the default policy. (test_policy).
     **/
    public static final PolicyLocation DEFAULT_POLICY = PolicyLocation.make("test_policy", "/xml/policies/test_policy.xml");
    /**
     * The file location of the policy with full access to all attributes.
     **/
    public static final PolicyLocation POLICY_FULL = PolicyLocation.make("policy_full", "/xml/policies/policy_full.xml");
    /**
     * The file location of the policy with full access to all attributes.
     **/
    public static final PolicyLocation POLICY_LIGHT = PolicyLocation.make("policy_light", "/xml/policies/policy_light.xml");
    /**
     * The file location of the policy with minimal content, that still performs nomenclature resolution tests.
     **/
    public static final PolicyLocation BOM_POLICY = PolicyLocation.make("bom_policy", "/xml/policies/bom_policy.xml");
    /**
     * The file location of the full policy for a R01 report.
     **/
    public static final PolicyLocation R01_POLICY_FULL = PolicyLocation.make("R01_policy_full", "/xml/policies/r01report/R01_policy_full.xml");
    /**
     * The file location of the light policy for a R01 report.
     **/
    public static final PolicyLocation R01_POLICY_LIGHT = PolicyLocation.make("R01_policy_light", "/xml/policies/r01report/R01_policy_light.xml");
    /**
     * The file location of the full policy for a R03 report.
     **/
    public static final PolicyLocation R03_POLICY_FULL = PolicyLocation.make("R03_policy_full", "/xml/policies/r03report/R03_policy_full.xml");
    /**
     * The file location of the light policy for a R03 report.
     **/
    public static final PolicyLocation R03_POLICY_LIGHT = PolicyLocation.make("R03_policy_light", "/xml/policies/r03report/R03_policy_light.xml");
    /**
     * The file location of the full policy for a R03 report.
     **/
    public static final PolicyLocation R07_POLICY_FULL = PolicyLocation.make("R07_policy_full", "/xml/policies/r07report/R07_policy_full.xml");
    /**
     * The file location of the light policy for a R03 report.
     **/
    public static final PolicyLocation R07_POLICY_LIGHT = PolicyLocation.make("R07_policy_light", "/xml/policies/r07report/R07_policy_light.xml");
    /**
     * The file location of the full policy for a R10 report.
     **/
    public static final PolicyLocation R10_POLICY_FULL = PolicyLocation.make("R10_policy_full", "/xml/policies/r10report/R10_policy_full.xml");
    /**
     * The file location of the light policy for a R10 report.
     **/
    public static final PolicyLocation R10_POLICY_LIGHT = PolicyLocation.make("R10_policy_light", "/xml/policies/r10report/R10_policy_light.xml");
    /**
     * The file location of the full policy for a R11 report.
     **/
    public static final PolicyLocation R11_POLICY_FULL = PolicyLocation.make("R11_policy_full", "/xml/policies/r11report/R11_policy_full.xml");
    /**
     * The file location of the light policy for a R11 report.
     **/
    public static final PolicyLocation R11_POLICY_LIGHT = PolicyLocation.make("R11_policy_light", "/xml/policies/r11report/R11_policy_light.xml");
    /**
     * The file location of the full policy for a R13 report.
     **/
    public static final PolicyLocation R13_POLICY_FULL = PolicyLocation.make("R13_policy_full", "/xml/policies/r13report/R13_policy_full.xml");
    /**
     * The file location of the light policy for a R13 report.
     **/
    public static final PolicyLocation R13_POLICY_LIGHT = PolicyLocation.make("R13_policy_light", "/xml/policies/r13report/R13_policy_light.xml");
    /**
     * The file location of the full policy for a R15 report.
     **/
    public static final PolicyLocation R15_POLICY_FULL = PolicyLocation.make("R15_policy_full", "/xml/policies/r15report/R15_policy_full.xml");
    /**
     * The file location of the light policy for a R15 report.
     **/
    public static final PolicyLocation R15_POLICY_LIGHT = PolicyLocation.make("R15_policy_light", "/xml/policies/r15report/R15_policy_light.xml");
    /**
     * The file location of the full policy for a R16 report.
     **/
    public static final PolicyLocation R16_POLICY_FULL = PolicyLocation.make("R16_policy_full", "/xml/policies/r16report/R16_policy_full.xml");
    /**
     * The file location of the light policy for a R16 report.
     **/
    public static final PolicyLocation R16_POLICY_LIGHT = PolicyLocation.make("R16_policy_light", "/xml/policies/r16report/R16_policy_light.xml");
    /**
     * The file location of the full policy for a R17 report.
     **/
    public static final PolicyLocation R17_POLICY_FULL = PolicyLocation.make("R17_policy_full", "/xml/policies/r17report/R17_policy_full.xml");
    /**
     * The file location of the light policy for a R17 report.
     **/
    public static final PolicyLocation R17_POLICY_LIGHT = PolicyLocation.make("R17_policy_light", "/xml/policies/r17report/R17_policy_light.xml");
    /**
     * The file location of the full policy for a R19 report.
     **/
    public static final PolicyLocation R19_POLICY_FULL = PolicyLocation.make("R19_policy_full", "/xml/policies/r19report/R19_policy_full.xml");
    /**
     * The file location of the light policy for a R19 report.
     **/
    public static final PolicyLocation R19_POLICY_LIGHT = PolicyLocation.make("R19_policy_light", "/xml/policies/r19report/R19_policy_light.xml");
    /**
     * The file location of the full policy for a R20 report.
     **/
    public static final PolicyLocation R20_POLICY_FULL = PolicyLocation.make("R20_policy_full", "/xml/policies/r20report/R20_policy_full.xml");
    /**
     * The file location of the light policy for a R20 report.
     **/
    public static final PolicyLocation R20_POLICY_LIGHT = PolicyLocation.make("R20_policy_light", "/xml/policies/r20report/R20_policy_light.xml");
    /**
     * The file location of the full policy for a R21 report.
     **/
    public static final PolicyLocation R21_POLICY_FULL = PolicyLocation.make("R21_policy_full", "/xml/policies/r21report/R21_policy_full.xml");
    /**
     * The file location of the light policy for a R21 report.
     **/
    public static final PolicyLocation R21_POLICY_LIGHT = PolicyLocation.make("R21_policy_light", "/xml/policies/r21report/R21_policy_light.xml");
    /**
     * The file location of the full policy for a R22 report.
     **/
    public static final PolicyLocation R22_POLICY_FULL = PolicyLocation.make("R22_policy_full", "/xml/policies/r22report/R22_policy_full.xml");
    /**
     * The file location of the light policy for a R22 report.
     **/
    public static final PolicyLocation R22_POLICY_LIGHT = PolicyLocation.make("R22_policy_light", "/xml/policies/r22report/R22_policy_light.xml");

    /**
     * Flag to only build the objects once.
     **/
    private static boolean isPolicySetup;

    private static boolean isChangeSession;

    private static TcSession session;

    /**
     * Opens a connection. May fail if the default policy (policy_full.xml) does not exist on the TC server
     *
     * @return the session
     * @throws NoTeamcenterConnectionException Should not happen
     */
    public static TcSession getSession() throws NoTeamcenterConnectionException {
        if (session == null) {
            // Check the duration between current login and the previous one
            long theCurrentTimestamp = System.currentTimeMillis();
            if (theCurrentTimestamp < lastLogInTimeMs + LOGIN_DELAY) {
                long theWaitDuration = lastLogInTimeMs + LOGIN_DELAY - theCurrentTimestamp;
                log.info("Waiting for next login retry in order to wait during the TCServer initialization: " + theWaitDuration + "ms");
                try {
                    Thread.sleep(theWaitDuration);
                } catch (InterruptedException e) {
                    log.error("Sleep interrupted", e);
                }
            }

            // Save the current login time
            lastLogInTimeMs = System.currentTimeMillis();

            // Create the session (login is performed)
            session = new TcSession();
            session.login();
            try {
                session.setObjectPropPolicy(POLICY_FULL);
            } catch (InvalidConfigurationException e) {
                throw new RuntimeException("Unable to load properties", e);
            }
        }
        return session;
    }

    /**
     * Cleanly close the connection.
     *
     * @throws ServiceException Should not happen
     */
    @AfterClass
    public static void logoutTeamcenter() throws ServiceException {
        // Try to log out the current session
        if (session == null) {
            log.error("No session handle found to close the session. The session may not have been closed.");
        } else {
            session.close();
        }
    }

    /**
     * Declares the location of the property policy to be used throughout the daughter class's unit Tests.<br>
     * A default policy file location is provided by this class in the static constant DEFAULT_POLICY.
     *
     * @return the relative location of the property policy file.
     */
    public abstract PolicyLocation getPropertyPolicyIdentifier();

}
