using LSFE.Infrastructure.Model.Admin;
using LSFE.MobApp.Contracts;
using LSFE.MobApp.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace LSFE.MobApp.Services
{
    public class ApiClient<T> : IApiClient<T> where T : class
    {
        private readonly HttpClient _httpClient;
        private readonly string _baseEndpoint;
        private readonly JsonSerializerOptions _jsonOptions;
        public ApiClient(HttpClient httpClient, string baseEndpoint)
        {
            _httpClient = httpClient;
            _baseEndpoint = baseEndpoint;
            _jsonOptions = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
                WriteIndented = false
            };
        }
        public async Task<List<T>> GetAllAsync()
        {
            try
            {
                var response = await _httpClient.GetAsync(_baseEndpoint);
                response.EnsureSuccessStatusCode();

                var json = await response.Content.ReadAsStringAsync();
                return JsonSerializer.Deserialize<List<T>>(json, _jsonOptions) ?? new List<T>();
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error in GetAllAsync: {ex.Message}");
                return new List<T>();
            }
        }
        public async Task<List<T>> GetWithQueryAsync(Dictionary<string, string> queryParams)
        {
            try
            {
                var query = string.Join("&", queryParams
                    .Where(kv => !string.IsNullOrEmpty(kv.Value))
                    .Select(kv => $"{kv.Key}={Uri.EscapeDataString(kv.Value)}"));

                var url = string.IsNullOrEmpty(query) ? _baseEndpoint : $"{_baseEndpoint}?{query}";
                var response = await _httpClient.GetAsync(url);
                response.EnsureSuccessStatusCode();

                var json = await response.Content.ReadAsStringAsync();
                return JsonSerializer.Deserialize<List<T>>(json, _jsonOptions);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error in GetWithQueryAsync: {ex.Message}");
                return null;
            }
        }
        public async Task<LoginResponse> LoginAsync(LoginRequest entity)
        {
            try
            {
                var json = JsonSerializer.Serialize(entity, _jsonOptions);
                var content = new StringContent(json, Encoding.UTF8, "application/json");

                var response = await _httpClient.PostAsync(_baseEndpoint, content);
                var responseJson = await response.Content.ReadAsStringAsync();

                return JsonSerializer.Deserialize<LoginResponse>(responseJson, _jsonOptions);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error in LoginAsync: {ex.Message}");
                return null;
            }
        }
        public async Task<T> GetByIdAsync(int id)
        {
            try
            {
                var response = await _httpClient.GetAsync($"{_baseEndpoint}/{id}");
                response.EnsureSuccessStatusCode();

                var json = await response.Content.ReadAsStringAsync();
                return JsonSerializer.Deserialize<T>(json, _jsonOptions);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error in GetByIdAsync: {ex.Message}");
                return null;
            }
        }
        public async Task<ApiResponse<T>> CreateAsync(T entity)
        {
            try
            {
                var json = JsonSerializer.Serialize(entity, _jsonOptions);
                var content = new StringContent(json, Encoding.UTF8, "application/json");

                var response = await _httpClient.PostAsync(_baseEndpoint, content);
                var responseJson = await response.Content.ReadAsStringAsync();

                return JsonSerializer.Deserialize<ApiResponse<T>>(responseJson, _jsonOptions);
            }
            catch (Exception ex)
            {
                return new ApiResponse<T>
                {
                    Success = false,
                    Message = ex.Message,
                    MessCode = 0
                };
            }
        }
        public async Task<ApiResponse<T>> CreateAttendanceAsync(T entity)
        {
            try
            {
                using var form = new MultipartFormDataContent();

                // Convert your entity (Attendance) into key-value form fields
                foreach (var prop in typeof(T).GetProperties())
                {
                    var value = prop.GetValue(entity);
                    if (value != null)
                    {
                        // Skip SignatureImage byte array - we'll send the files instead
                        if (prop.Name == "SignatureImage")
                            continue;

                        // Convert Guid to string for AppAttendanceId
                        if (prop.Name == "AppAttendanceId" && value is Guid guid)
                        {
                            form.Add(new StringContent(guid.ToString()), prop.Name);
                        }
                        // Handle DateTime properties with ISO format
                        else if (value is DateTime dateTime)
                        {
                            form.Add(new StringContent(dateTime.ToString("o")), prop.Name); // ISO 8601 format
                        }
                        else
                        {
                            form.Add(new StringContent(value.ToString()), prop.Name);
                        }
                    }
                }

                // Add Time-In photo if exists
                var fileInProp = typeof(T).GetProperty("SignatureFileNameIn");
                if (fileInProp != null)
                {
                    var fileName = fileInProp.GetValue(entity)?.ToString();
                    if (!string.IsNullOrEmpty(fileName))
                    {
                        var filePath = Path.Combine(FileSystem.AppDataDirectory, fileName);
                        if (File.Exists(filePath))
                        {
                            var stream = File.OpenRead(filePath);
                            var fileContent = new StreamContent(stream);
                            fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
                            form.Add(fileContent, "photoFileIn", fileName);
                        }
                        else
                        {
                            Debug.WriteLine($"Time-In file not found: {filePath}");
                        }
                    }
                }

                // Add Time-Out photo if exists
                var fileOutProp = typeof(T).GetProperty("SignatureFileNameOut");
                if (fileOutProp != null)
                {
                    var fileName = fileOutProp.GetValue(entity)?.ToString();
                    if (!string.IsNullOrEmpty(fileName))
                    {
                        var filePath = Path.Combine(FileSystem.AppDataDirectory, fileName);
                        if (File.Exists(filePath))
                        {
                            var stream = File.OpenRead(filePath);
                            var fileContent = new StreamContent(stream);
                            fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
                            form.Add(fileContent, "photoFileOut", fileName);
                        }
                        else
                        {
                            Debug.WriteLine($"Time-Out file not found: {filePath}");
                        }
                    }
                }

                var response = await _httpClient.PostAsync(_baseEndpoint, form);
                var responseJson = await response.Content.ReadAsStringAsync();

                if (!response.IsSuccessStatusCode)
                {
                    return new ApiResponse<T>
                    {
                        Success = false,
                        Message = $"API returned {response.StatusCode}: {responseJson}",
                        MessCode = 0
                    };
                }

                return JsonSerializer.Deserialize<ApiResponse<T>>(responseJson, _jsonOptions);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"CreateWithPhotoAsync Exception: {ex.ToString()}");
                return new ApiResponse<T>
                {
                    Success = false,
                    Message = ex.Message,
                    MessCode = 0
                };
            }
        }
        public async Task<ApiResponse<T>> CreateCoveragePlanAsync(T entity)
        {
            try
            {
                using var form = new MultipartFormDataContent();

                // Convert your entity (MRRawPlan) into key-value form fields
                foreach (var prop in typeof(T).GetProperties())
                {
                    var value = prop.GetValue(entity);
                    if (value != null)
                    {
                        // Skip SignatureBase64 if it exists - we'll send the file instead
                        if (prop.Name == "SignatureBase64")
                            continue;

                        // Convert Guid to string
                        if (value is Guid guid)
                        {
                            form.Add(new StringContent(guid.ToString()), prop.Name);
                        }

                        // Handle DateTime properties with ISO format
                        else if (value is DateTime dateTime)
                        {
                            form.Add(new StringContent(dateTime.ToString("o")), prop.Name); // ISO 8601 format
                        }
                        // Handle boolean
                        else if (value is bool boolValue)
                        {
                            form.Add(new StringContent(boolValue.ToString().ToLower()), prop.Name);
                        }
                        else
                        {
                            form.Add(new StringContent(value.ToString()), prop.Name);
                        }
                    }
                }

                // Add Signature photo if exists
                var fileNameProp = typeof(T).GetProperty("SignatureFileName");
                if (fileNameProp != null)
                {
                    var fileName = fileNameProp.GetValue(entity)?.ToString();
                    if (!string.IsNullOrEmpty(fileName))
                    {
                        var filePath = Path.Combine(FileSystem.AppDataDirectory, fileName);
                        if (File.Exists(filePath))
                        {
                            var stream = File.OpenRead(filePath);
                            var fileContent = new StreamContent(stream);
                            fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png");
                            form.Add(fileContent, "photoFile", fileName);
                        }
                        else
                        {
                            Debug.WriteLine($"Signature file not found: {filePath}");
                            return new ApiResponse<T>
                            {
                                Success = false,
                                Message = $"Signature file not found at: {filePath}",
                                MessCode = 0
                            };
                        }
                    }
                    else
                    {
                        Debug.WriteLine("SignatureFileName is null or empty");
                    }
                }

                var response = await _httpClient.PostAsync(_baseEndpoint, form);
                var responseJson = await response.Content.ReadAsStringAsync();

                if (!response.IsSuccessStatusCode)
                {
                    Debug.WriteLine($"API Error: {response.StatusCode} - {responseJson}");
                    return new ApiResponse<T>
                    {
                        Success = false,
                        Message = $"API returned {response.StatusCode}: {responseJson}",
                        MessCode = 0
                    };
                }

                return JsonSerializer.Deserialize<ApiResponse<T>>(responseJson, _jsonOptions);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"CreateWithPhotoAsync Exception: {ex.ToString()}");
                return new ApiResponse<T>
                {
                    Success = false,
                    Message = ex.Message,
                    MessCode = 0
                };
            }
        }
        public async Task<T> GetByIdAsync(Guid id)
        {
            try
            {
                var response = await _httpClient.GetAsync($"{_baseEndpoint}/{id}");
                response.EnsureSuccessStatusCode();

                var json = await response.Content.ReadAsStringAsync();
                Debug.WriteLine($"GetByIdAsync Response: {json}");

                return JsonSerializer.Deserialize<T>(json, _jsonOptions);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error in GetByIdAsync: {ex.Message}");
                return null;
            }
        }      
        public async Task<ApiResponse<T>> UpdateAsync(Guid id, T entity)
        {
            try
            {
                var json = JsonSerializer.Serialize(entity, _jsonOptions);
                Debug.WriteLine($"UpdateAsync Request: {json}");

                var content = new StringContent(json, Encoding.UTF8, "application/json");

                var response = await _httpClient.PutAsync($"{_baseEndpoint}/{id}", content);
                var responseJson = await response.Content.ReadAsStringAsync();

                Debug.WriteLine($"UpdateAsync Response: {responseJson}");

                if (!response.IsSuccessStatusCode)
                {
                    return new ApiResponse<T>
                    {
                        Success = false,
                        Message = $"Server returned {response.StatusCode}: {responseJson}",
                        MessCode = (int)response.StatusCode
                    };
                }

                return JsonSerializer.Deserialize<ApiResponse<T>>(responseJson, _jsonOptions);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error in UpdateAsync: {ex.Message}");
                return new ApiResponse<T>
                {
                    Success = false,
                    Message = ex.Message,
                    MessCode = 0
                };
            }
        }
        public async Task<ApiResponse<T>> DeleteAsync(Guid id)
        {
            try
            {
                var response = await _httpClient.DeleteAsync($"{_baseEndpoint}/{id}");
                var responseJson = await response.Content.ReadAsStringAsync();

                Debug.WriteLine($"DeleteAsync Response: {responseJson}");

                if (!response.IsSuccessStatusCode)
                {
                    return new ApiResponse<T>
                    {
                        Success = false,
                        Message = $"Server returned {response.StatusCode}: {responseJson}",
                        MessCode = (int)response.StatusCode
                    };
                }

                return JsonSerializer.Deserialize<ApiResponse<T>>(responseJson, _jsonOptions) ?? new ApiResponse<T>
                {
                    Success = true,
                    Message = "Deleted successfully",
                    MessCode = 200
                };
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error in DeleteAsync: {ex.Message}");
                return new ApiResponse<T>
                {
                    Success = false,
                    Message = ex.Message,
                    MessCode = 0
                };
            }
        }
    }
}