Imports System.Data.SqlClient
Imports i3Screen
Imports Logic.DateExtensions

Public Class RequestTest
    Inherits System.Web.UI.Page

    Property contractId As Integer
    Property testId As Integer

    Protected Sub Page_Load() Handles Me.Load
        Try
            contractId = Logic.Conversion.ToInteger(Request.Params("cid"))
            testId = Logic.Conversion.ToInteger(Request.Params("tid"))

            Master.CurrentClient.VerifyContractAccess(contractId)
            Dim perms = Master.CurrentClient.Permissions
            If Not perms.Contains("Request Drug Test") Then Throw New HttpException(403, "Forbidden")

            Master.SetParentPage("DrugAlcoholTests.aspx?cid=" & contractId)

            If Not Page.IsPostBack Then
                ddlReason.Items.AddRange({New ListItem()}.Concat(
                    From reason In Logic.DrugAlcoholTestType.ListDrug()
                    Select New ListItem(reason.Value, reason.Key)).ToArray())

                If testId > 0 Then
                    _Prefill(testId)
                End If
            End If

        Catch ex As Exception
            Dim errorId = Logic.Error.Log(ex)
            Response.Redirect("/Error.aspx?id=" & errorId)
        End Try
    End Sub

    Private Sub btnCancel_Click() Handles btnCancel.Click
        Response.Redirect("DrugAlcoholTests.aspx?cid=" & contractId)
    End Sub

    Private Sub btnSubmit_Click() Handles btnSubmit.Click
        If Not Page.IsValid Then Exit Sub

        Try
            Using connection As New SqlConnection(Logic.Database.connectionString)
                connection.Open()

                Dim logId = _CreateLogEntry(connection)
                Dim request = _CreateRequest(connection)
                request.ReferenceId = logId

                _UpdateLogPayload(request.payload, logId, connection)

                '    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
                Dim responseString = request.Send()

                _UpdateLogResponse(responseString, logId, connection)
                Dim response As New BackgroundCheckResponse(responseString)

                If String.IsNullOrEmpty(response.ErrorReason) Then
                    Dim test = _CreateOurTest(response, connection)
                    _EmailOurTest(response, test, connection)
                Else
                    _EmailError(response.ErrorReason, connection)
                    Throw New Exception(response.ErrorReason)
                End If

            End Using
        Catch ex As Exception
            Dim errorId = Logic.Error.Log(ex)
            Response.Redirect("/Error.aspx?id=" & errorId)
        End Try

        phSubmitted.Visible = True
        phForm.Visible = False
    End Sub

    ' Prefill the form based on a pending test
    Private Sub _Prefill(testId As Integer)

        Dim test As New Logic.DrugAlcoholTest(testId)
        If test.contractID <> contractId Then
            Throw New Exception("Drug test not found in contract.")
        End If

        ' Parse the driver name from the test
        If test.driverName.Contains(",") Then
            Dim parts = Split(test.driverName, ",")
            txtNameLast.Text = parts(0)
            Dim otherNames = parts(1).Trim()
            If otherNames.Contains(" ") Then
                parts = Split(otherNames)
                txtNameFirst.Text = parts(0)
                txtNameMiddle.Text = parts(1)
            Else
                txtNameFirst.Text = otherNames
            End If
        Else
            Dim parts = Split(test.driverName)
            txtNameFirst.Text = parts.First()
            If parts.Length = 2 Then
                txtNameLast.Text = parts.Last()
            ElseIf parts.Length > 2 Then
                txtNameMiddle.Text = parts(1)
                txtNameLast.Text = parts(2)
            End If
        End If

        ' More defaults from the test
        ddlReason.SelectedValue = test.testTypeID
        txtDLNumber.Text = test.dlNumber
        ddlDLState.SelectedValue = test.dlState
        ddlState.SelectedValue = test.dlState
        ddlFederalAgency.SelectedValue = If(test.isDot.HasValue And test.isDot, "TCDOTU", "TC5UDOTLIKE")

        ' If there's a driver, override test values set above
        If test.driverID > 0 Then
            Dim driver As New Logic.Driver(test.driverID)
            txtNameFirst.Text = driver.firstName
            txtNameMiddle.Text = driver.middleName
            txtNameLast.Text = driver.lastName
            txtDLNumber.Text = driver.dlNumber
            ddlDLState.SelectedValue = driver.dlState
            txtDateBirth.Text = driver.dob.FormatForHtml5()
            txtPhone.Text = driver.phone1
            txtEmail.Text = driver.email
            txtAddress.Text = driver.address1
            txtAddress2.Text = driver.address2
            txtCity.Text = driver.city
            ddlState.SelectedValue = driver.state
            txtZip.Text = driver.zip
        End If

        ' Set test reason, from test and converted for i3screen
        Using connection As New SqlConnection(Logic.Database.ConnectionString) 'My.Settings.connectionString)
            connection.Open()
            Dim cmd As New SqlCommand("SELECT ISNULL(i3Name,'') FROM DrugAlcoholTestType WHERE ID=@typeId", connection)
            cmd.Parameters.AddWithValue("typeId", test.testTypeID)
            ddlReason.SelectedValue = cmd.ExecuteScalar()
        End Using

    End Sub

    ' Create the test in our system
    Private Function _CreateOurTest(response As BackgroundCheckResponse, connection As SqlConnection) As Logic.DrugAlcoholTest

        ' The test we're saving in our system
        Dim test As Logic.DrugAlcoholTest
        If testId > 0 Then
            ' If we prefilled from a test, we'll modify it and overwrite anything we changed.
            test = New Logic.DrugAlcoholTest(testId)
        Else
            test = New Logic.DrugAlcoholTest()
        End If

        ' Set the data
        With test
            .testDate = Logic.Conversion.ToDate(txtTestDate.Text)
            .testTypeID = ddlReason.SelectedValue
            .collectionFacilityID = 0 ' ddlClinic.SelectedValue,
            .contractID = contractId
            .billable = False
            .notes = txtNotes.Text
            .status = "Scheduled"
            .dlNumber = txtDLNumber.Text
            .dlState = ddlState.SelectedValue
            .i3ScreenId = response.ProviderReferenceId
        End With

        ' Pull driver info into the test.
        Try
            Dim cmd As New SqlCommand(
                "SELECT Id, ContractID, (FirstName+' '+LTrim(MiddleName+' '+LastName)+' '+Suffix) AS FullName, SSN
                FROM Driver WHERE Terminated=0 AND DLNumber=@dlNumber AND ContractId=@contractId", connection)
            cmd.Parameters.AddWithValue("dlNumber", txtDLNumber.Text)
            cmd.Parameters.AddWithValue("contractId", contractId)
            Using dReader = cmd.ExecuteReader()
                If dReader.Read() Then
                    test.driverID = dReader("ID")
                    test.driverName = CStr(dReader("FullName")).Trim()
                    If dReader.Read() Then
                        Throw New Exception("More than one active driver found for DLNumber.")
                    End If
                Else
                    test.driverID = 0
                    test.driverName = String.Format("{0} {1}", txtNameFirst.Text, txtNameLast.Text)
                End If
            End Using
        Catch ex As Exception
            _EmailError("The drug test was requested, but an error occurred: " & ex.Message, connection)
            Throw
        End Try

        ' Save the test
        Using transaction = connection.BeginTransaction()
            test.Save("[Web: " & Master.CurrentClient.username & "]", connection, transaction)
            transaction.Commit()
        End Using

        Return test
    End Function

    Private Sub _EmailOurTest(response As BackgroundCheckResponse, test As Logic.DrugAlcoholTest, connection As SqlConnection)

        Dim cmd As New SqlCommand("", connection)

        Dim senderId As Integer
        Dim subject As String
        Dim template As String
        cmd.CommandText = "SELECT emailDrugTestScheduledFromId, emailDrugTestScheduledSubject, emailDrugTestScheduledBody FROM Company"
        Using dReader = cmd.ExecuteReader()
            dReader.Read()
            senderId = dReader(0)
            subject = dReader(1)
            template = dReader(2)
        End Using
        
        Dim customerName As String
        cmd.CommandText = "SELECT Name FROM ServiceContract sc LEFT JOIN Customer cust ON cust.ID=sc.CustomerID WHERE sc.ID=@contractId"
        cmd.Parameters.AddWithValue("contractId", contractId)
        customerName = cmd.ExecuteScalar()

        Dim params = New Dictionary(Of String, String) From {
            {"CONTRACTID", contractId},
            {"CUSTOMERNAME", customerName},
            {"TESTID", test.id},
            {"DRIVERNAME", test.driverName},
            {"SCHEDULEURL", response.SchedulingUrl}}
        For Each param In params
            subject = subject.Replace("#" & param.Key & "#", param.Value)
            template = template.Replace("#" & param.Key & "#", param.Value)
        Next
        subject = subject.Replace("'", "") ' in case other software doesn't sanitize
        template = template.Replace("'", "") ' in case other software doesn't sanitize

        Dim email As New Logic.AutomationServer_EmailsSent() With {
            .EmailFromId = senderId,
            .EmailTo = String.Join(";", {txtEmail.Text, txtEmailCC.Text, "csat@trucksafety.com"}.Except({""})),
            .EmailSubject = subject, .KeepSubject = True,
            .EmailBody = template}
        email.Create(connection)
    End Sub
    
    Private Sub _EmailError(message As String, connection As SqlConnection)
        Dim emailError As New Logic.AutomationServer_EmailsSent() With {
            .EmailTo = "nathan@comptechweb.com; csat@trucksafety.com",
            .EmailSubject = "Drug Test Request Error",
            .EmailBody = message}
        emailError.Create(connection)
    End Sub

    Private Function _GetOurTestTypeId(i3Name As String, connection As SqlConnection) As Integer
        Dim cmd As New SqlCommand("SELECT ID FROM DrugAlcoholTestType WHERE i3Name=@i3Name", connection)
        cmd.Parameters.AddWithValue("i3Name", i3Name)
        Return cmd.ExecuteScalar()
    End Function

    Private Function _CreateRequest(connection As SqlConnection) As BackgroundCheckRequest
        Dim cmd As New SqlCommand("", connection)
        cmd.Parameters.Add("itemId", SqlDbType.BigInt)

        Dim customerName As String
        Dim i3ScreenOrgId As String
        Dim labAccountNumber As String
        Dim i3ScreenLocationCode As String
        cmd.CommandText = 
            "SELECT sc.i3ScreenOrgId, sc.LabAccountNumber, cust.Name, sc.i3ScreenLocationCode
            FROM ServiceContract sc LEFT JOIN Customer cust ON cust.ID=sc.CustomerID
            WHERE sc.ID=@itemId"
        cmd.Parameters("itemId").Value = contractId
        Using dReader = cmd.ExecuteReader()
            If Not dReader.Read() Then Throw New Exception("Invalid Contract Id")
            customerName = dReader("Name")
            i3ScreenOrgId = dReader("i3ScreenOrgId")
            labAccountNumber = dReader("LabAccountNumber")
            i3ScreenLocationCode = dReader("i3ScreenLocationCode")
        End Using
        If labAccountNumber.StartsWith("DOT") Then labAccountNumber = Mid(labAccountNumber, 4).Trim()
        
        Dim request As New BackgroundCheckRequest With {
            .userId = My.Settings.i3Screen_LiveUserId,
            .password = My.Settings.i3Screen_LivePassword,
            .CustomerName = customerName,
            .CustomerOrgId = i3ScreenOrgId,
            .ApplicantFirstName = txtNameFirst.Text,
            .ApplicantMiddleName = txtNameMiddle.Text,
            .ApplicantLastName = txtNameLast.Text,
            .ApplicantTelephone = txtPhone.Text,
            .ApplicantCountry = "US",
            .ApplicantZipCode = txtZip.Text,
            .ApplicantState = ddlState.SelectedValue,
            .ApplicantCity = txtCity.Text,
            .ApplicantStreet = txtAddress.Text,
            .ApplicantStreet2 = txtAddress2.Text,
            .ApplicantSSN = ddlDLState.SelectedValue & txtDLNumber.Text,
            .LocationReferenceId = i3ScreenLocationCode,
            .LabAccountNumber = labAccountNumber,
            .IntegrationPartnerName = "TRANSPORTATION COMPLIANCE SERVICES USA",
            .ReasonForTest = _UsToI3_Reason(ddlReason.SelectedValue, connection),
            .TestTypePackageCode = ddlTestType.SelectedValue,
            .ExpirationDate = Logic.Conversion.ToDate(txtOrderExpires.Text),
            .DotAgency = ddlFederalAgency.SelectedValue,
            .ObservedCollectionRequired = Logic.Conversion.ToBoolean(ddlObservedCollectionRequired.SelectedValue)
            }
        Return request
    End Function
    
    Private Function _CreateLogEntry(connection As SqlConnection) As Integer
        Dim cmd As New SqlCommand(
            "INSERT INTO i3ScreenLog (timestamp,direction,method,payload)
            VALUES (GETDATE(),'out','BackgroundCheck','');
            SELECT @@IDENTITY;", connection)
        Return cmd.ExecuteScalar()
    End Function
    Private Sub _UpdateLogPayload(payload As String, logId As Integer, connection As SqlConnection)
        Dim cmd As New SqlCommand("UPDATE i3ScreenLog SET payload=@payload WHERE id=@logId", connection)
        cmd.Parameters.AddWithValue("logId", logId)
        cmd.Parameters.AddWithValue("payload", payload)
        cmd.ExecuteNonQuery()
    End Sub
    Private Sub _UpdateLogResponse(response As String, logId As Integer, connection As SqlConnection)
        Dim cmd As New SqlCommand("UPDATE i3ScreenLog SET response=@response WHERE id=@logId", connection)
        cmd.Parameters.AddWithValue("logId", logId)
        cmd.Parameters.AddWithValue("response", response)
        cmd.ExecuteNonQuery()
    End Sub

    Private Function _UsToI3_Reason(reasonId As Integer, connection As SqlConnection) As String
        Dim cmd As New SqlCommand("SELECT i3Name FROM DrugAlcoholTestType WHERE id=@typeId", connection)
        cmd.Parameters.AddWithValue("typeId", reasonId)
        Return cmd.ExecuteScalar()
    End Function

End Class