Imports System.Net
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Text
Imports System.Threading.Tasks
Imports Models
Imports Newtonsoft.Json.Linq

Public Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not IsPostBack Then
            mensajeError.InnerText = Convert.ToString(Request.QueryString("certError"))
        End If
    End Sub

    Private Async Sub btnAcceso_Click(sender As Object, e As EventArgs) Handles btnAcceso.Click
        mensajeError.InnerText = ""

        Dim resultIden As String = Await CredNet(Usuario.Value)
        Dim RespIden As Models.ResultadoIdentificacion = Nothing

        If resultIden <> "error" Then
            Dim client = HttpClientFactory.Create()
            client.BaseAddress = New Uri(UtilAntifraude.urlSwagger())
            client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", Convert.ToString(Session("token")))

            Dim loginResponse = Await client.GetAsync("api/ResultadoIdentificacion/nif/" + resultIden + "/Origen/WEBINTRANET")
            Dim responseContent = Await loginResponse.Content.ReadAsStringAsync()

            RespIden = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Models.ResultadoIdentificacion)(responseContent)
        End If

        If RespIden Is Nothing Then
            divLoadingHome.Style.Item("display") = "none"
            mensajeError.InnerText = "No se pudo identificar al usuario."
            Return
        End If

        ProcesarResultadoIdentificacion(RespIden, Usuario.Value)
    End Sub

    Private Async Function CredNet(Nif As String) As Task(Of String)
        Try
            Dim contr As String = Contrasena.Value

            Dim client = HttpClientFactory.Create()
            client.BaseAddress = New Uri(UtilAntifraude.urlSwagger())

            Dim loginPayload = "{""NombreUsuario"":""" + Nif + """,""Contraseña"":""" + contr + """, ""Origen"":""Intranet""}"
            Dim loginContent As StringContent = New StringContent(loginPayload, Encoding.UTF8, "application/json")
            Dim loginResponse = Await client.PostAsync("api/Auth/login", loginContent)
            Dim responseContent = Await loginResponse.Content.ReadAsStringAsync()

            If loginResponse.IsSuccessStatusCode Then
                Dim parsedJson = JObject.Parse(responseContent)
                Session("token") = If(parsedJson("token")?.ToString(), If(parsedJson("Token")?.ToString(), ""))

                Dim us = parsedJson("user")
                If us Is Nothing Then us = parsedJson("User")

                If us IsNot Nothing Then
                    Return If(us("nif")?.ToString(),
                           If(us("NIF")?.ToString(),
                           If(us("dni")?.ToString(),
                           If(us("DNI")?.ToString(), ""))))
                End If

                Return "error"
            Else
                Return "error"
            End If
        Catch
            Return "error"
        End Try
    End Function

    Private Sub ProcesarResultadoIdentificacion(respIden As Models.ResultadoIdentificacion, usuarioOriginal As String)
        If respIden Is Nothing Then
            divLoadingHome.Style.Item("display") = "none"
            mensajeError.InnerText = "No se pudo identificar al usuario."
            Return
        End If

        Select Case respIden.resultado.ToString()
            Case "0"
                Dim Nombre As String = respIden.Personas(0).Nombre
                Dim Nif As String = respIden.Personas(0).Dni

                Session.Add("Nombre", Nombre)
                Session.Add("usuario", Nif)
                Session.Add("Persona", respIden)

                CargarNotificaciones(respIden)

                If Not String.IsNullOrWhiteSpace(usuarioOriginal) AndAlso usuarioOriginal.Length > 1 Then
                    If Not "0123456789".Contains(usuarioOriginal.Substring(1, 1)) Then
                        Session.Add("LDAP", usuarioOriginal)
                    End If
                End If

                If respIden.Personas.Count > 1 Then
                    Response.Redirect("selModo.aspx", False)
                    Context.ApplicationInstance.CompleteRequest()
                Else
                    Session.Add("modo", "PROPIO")
                    Session.Add("usuariosSeleccionados", Nif.Split(",").ToList())
                    Response.Redirect("home.aspx", False)
                    Context.ApplicationInstance.CompleteRequest()
                End If

            Case "1"
                divLoadingHome.Style.Item("display") = "none"
                mensajeError.InnerText = "Usuario incorrecto"

            Case "2"
                divLoadingHome.Style.Item("display") = "none"
                mensajeError.InnerText = "Contraseña incorrecta"

            Case "3"
                divLoadingHome.Style.Item("display") = "none"
                mensajeError.InnerText = respIden.errores.ToString()

            Case Else
                divLoadingHome.Style.Item("display") = "none"
                mensajeError.InnerText = "Error de identificación no controlado."
        End Select
    End Sub

    Private Sub CargarNotificaciones(respIden As Models.ResultadoIdentificacion)
        Dim listpersonas = respIden.Personas.ToList()
        Dim numAsistenciasPendientes = 0
        Dim listaPersonasIncidenciasPendientes As List(Of String) = New List(Of String)

        If listpersonas.Count > 1 Then
            Dim cont = 0

            For Each persona As Models.Personal In listpersonas
                If cont = 0 Then
                    cont += 1
                Else
                    numAsistenciasPendientes += persona.NumeroInciPorAceptar
                    If persona.NumeroInciPorAceptar > 0 Then
                        listaPersonasIncidenciasPendientes.Add(persona.Dni)
                    End If
                End If
            Next

            If numAsistenciasPendientes > 0 Then
                Session.Add("nuIncidenciasPendientes", numAsistenciasPendientes)
                Session.Add("listaPersonasIncPend", listaPersonasIncidenciasPendientes)
                Session.Add("fechaIniIncidenciasPendientes", respIden.FeIniInciPorAceptar.ToString("yyyy-MM-dd"))
                Session.Add("fechaFinIncidenciasPendientes", respIden.FeFinInciPorAceptar.ToString("yyyy-MM-dd"))
                Session.Add("mostrarAviso", True)
            End If
        End If
    End Sub

    <System.Web.Services.WebMethod(EnableSession:=True)>
    Public Shared Async Function cargarListado(usu As String, token As String) As Task(Of String)
        Return Await cargarListadoInterno(HttpContext.Current, usu, token)
    End Function

    <System.Web.Services.WebMethod(EnableSession:=True)>
    Public Shared Async Function cargarListadoCertificado(dni As String) As Task(Of String)
        If String.IsNullOrWhiteSpace(dni) Then
            Return "No se pudo obtener el DNI del certificado."
        End If

        Dim currentContext = HttpContext.Current
        If currentContext Is Nothing Then
            Return "No se pudo recuperar el contexto de sesión del acceso."
        End If

        If currentContext.Session Is Nothing Then
            Return "No se pudo recuperar la sesión del acceso con certificado."
        End If

        Dim endpoint As String = ConfigurationManager.AppSettings("CertLoginEndpoint")
        If String.IsNullOrWhiteSpace(endpoint) Then
            endpoint = "api/Auth/login-cert-proxy"
        End If

        Dim payload = "{""Dni"":""" & EscapeJson(dni.Trim()) & """}"
        Dim lastError As String = "No se pudo conectar con el servicio de autenticación."

        For Each baseAddress In ObtenerSwaggerBaseAddresses()
            Try
                Dim client = HttpClientFactory.Create()
                client.BaseAddress = baseAddress
                client.Timeout = TimeSpan.FromSeconds(15)

                Using loginContent As New StringContent(payload, Encoding.UTF8, "application/json")
                    Dim loginResponse = Await client.PostAsync(endpoint, loginContent)
                    Dim responseContent = Await loginResponse.Content.ReadAsStringAsync()

                    If Not loginResponse.IsSuccessStatusCode Then
                        If Not String.IsNullOrWhiteSpace(responseContent) Then
                            Return responseContent
                        End If

                        Return "Error en el acceso con certificado."
                    End If

                    Dim parsedJson = JObject.Parse(responseContent)
                    Dim token = If(parsedJson("token")?.ToString(), If(parsedJson("Token")?.ToString(), ""))

                    Dim us = parsedJson("user")
                    If us Is Nothing Then us = parsedJson("User")

                    Dim nif = ""
                    If us IsNot Nothing Then
                        nif = If(us("nif")?.ToString(),
                             If(us("NIF")?.ToString(),
                             If(us("dni")?.ToString(),
                             If(us("DNI")?.ToString(), ""))))
                    End If

                    If String.IsNullOrWhiteSpace(token) OrElse String.IsNullOrWhiteSpace(nif) Then
                        Return "Respuesta inválida del servicio de autenticación."
                    End If

                    Try
                        Return Await cargarListadoInterno(currentContext, nif, token)
                    Catch ex As Exception
                        Return "Error interno completando el acceso con certificado: " & ex.Message
                    End Try
                End Using
            Catch ex As Exception When TypeOf ex Is HttpRequestException OrElse
                TypeOf ex Is TaskCanceledException OrElse
                TypeOf ex Is InvalidOperationException OrElse
                TypeOf ex Is UriFormatException
                lastError = ex.Message
            End Try
        Next

        Return "No se pudo conectar con el servicio de autenticación configurado: " & lastError
    End Function

    Private Shared Iterator Function ObtenerSwaggerBaseAddresses() As IEnumerable(Of Uri)
        Dim seen As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)

        For Each candidate In ObtenerSwaggerBaseAddressCandidates()
            Dim normalizedCandidate = candidate.Trim()
            If normalizedCandidate = "" Then
                Continue For
            End If

            Dim baseUri As Uri = Nothing
            If Not Uri.TryCreate(normalizedCandidate, UriKind.Absolute, baseUri) Then
                Continue For
            End If

            Dim key = baseUri.AbsoluteUri.TrimEnd("/"c)
            If seen.Add(key) Then
                Yield baseUri
            End If
        Next
    End Function

    Private Shared Iterator Function ObtenerSwaggerBaseAddressCandidates() As IEnumerable(Of String)
        Dim configuredUrl = UtilAntifraude.urlSwagger()
        If Not String.IsNullOrWhiteSpace(configuredUrl) Then
            Yield configuredUrl

            Dim configuredUri As Uri = Nothing
            If Uri.TryCreate(configuredUrl, UriKind.Absolute, configuredUri) AndAlso
                String.Equals(configuredUri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) AndAlso
                EsHostLocal(configuredUri.Host) Then

                Dim httpBuilder As New UriBuilder(configuredUri) With {
                    .Scheme = Uri.UriSchemeHttp,
                    .Port = configuredUri.Port
                }

                Yield httpBuilder.Uri.AbsoluteUri
            End If
        End If

        Dim explicitFallback = ConfigurationManager.AppSettings("SwaggerVBFallback")
        If Not String.IsNullOrWhiteSpace(explicitFallback) Then
            Yield explicitFallback
        End If
    End Function

    Private Shared Function EsHostLocal(host As String) As Boolean
        Return String.Equals(host, "localhost", StringComparison.OrdinalIgnoreCase) OrElse
            String.Equals(host, "127.0.0.1", StringComparison.OrdinalIgnoreCase) OrElse
            String.Equals(host, "::1", StringComparison.OrdinalIgnoreCase)
    End Function

    Private Shared Function EscapeJson(valor As String) As String
        If valor Is Nothing Then Return ""
        Return valor.Replace("\", "\\").Replace("""", "\""").Replace(vbCrLf, "\n").Replace(vbLf, "\n").Replace(vbCr, "\n")
    End Function

    Private Shared Async Function cargarListadoInterno(context As HttpContext, usu As String, token As String) As Task(Of String)
        If context Is Nothing Then
            Return "No se pudo recuperar la sesión del usuario."
        End If

        Dim session = context.Session
        If session Is Nothing Then
            Return "No se pudo recuperar la sesión del usuario."
        End If

        session("token") = token

        Dim client = HttpClientFactory.Create()
        client.BaseAddress = New Uri(UtilAntifraude.urlSwagger())
        client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", token)

        Dim loginResponse = Await client.GetAsync("api/ResultadoIdentificacion/nif/" + usu + "/Origen/WEBINTRANET")
        Dim responseContent = Await loginResponse.Content.ReadAsStringAsync()
        Dim respIden = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Models.ResultadoIdentificacion)(responseContent)

        If respIden Is Nothing Then
            Return "No se pudo identificar al usuario."
        End If

        If respIden.Personas Is Nothing OrElse respIden.Personas.Count = 0 Then
            Return "La identificación no devolvió ninguna persona asociada."
        End If

        Dim resultado = Convert.ToString(respIden.resultado)

        Select Case resultado
            Case "0"
                Dim nombre = respIden.Personas(0).Nombre
                Dim nif = respIden.Personas(0).Dni

                session("Nombre") = nombre
                session("usuario") = nif
                session("Persona") = respIden

                Dim listpersonas = respIden.Personas.ToList()
                Dim numAsistenciasPendientes = 0
                Dim listaPersonasIncidenciasPendientes As List(Of String) = New List(Of String)

                If listpersonas.Count > 1 Then
                    Dim cont = 0
                    For Each persona As Models.Personal In listpersonas
                        If cont = 0 Then
                            cont += 1
                        Else
                            numAsistenciasPendientes += persona.NumeroInciPorAceptar
                            If persona.NumeroInciPorAceptar > 0 Then
                                listaPersonasIncidenciasPendientes.Add(persona.Dni)
                            End If
                        End If
                    Next

                    If numAsistenciasPendientes > 0 Then
                        session("nuIncidenciasPendientes") = numAsistenciasPendientes
                        session("listaPersonasIncPend") = listaPersonasIncidenciasPendientes
                        session("fechaIniIncidenciasPendientes") = respIden.FeIniInciPorAceptar.ToString("yyyy-MM-dd")
                        session("fechaFinIncidenciasPendientes") = respIden.FeFinInciPorAceptar.ToString("yyyy-MM-dd")
                        session("mostrarAviso") = True
                    End If
                End If

                If Not String.IsNullOrWhiteSpace(usu) AndAlso usu.Length > 1 Then
                    If Not "0123456789".Contains(usu.Substring(1, 1)) Then
                        session("LDAP") = usu
                    End If
                End If

                If respIden.Personas.Count > 1 Then
                    Return "selModo.aspx"
                End If

                session("modo") = "PROPIO"
                session("usuariosSeleccionados") = nif.Split(",").ToList()
                Return "home.aspx"

            Case "1"
                Return "Usuario incorrecto"

            Case "2"
                Return "Contraseña incorrecta"

            Case "3"
                Return Convert.ToString(respIden.errores)

            Case Else
                Return "Error de identificación no controlado"
        End Select
    End Function

End Class

Public Class NominaTrabajador
    Public Property idNominaTrabajador As String
    Public Property Descripcion As String
    Public Property MesNomina As Integer
End Class
