package com.example.myapplication;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.TimePickerDialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.ExifInterface;
import android.media.MediaRecorder;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.MediaStore;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.webkit.MimeTypeMap;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Filter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.core.util.Pair;
import androidx.lifecycle.ViewModelStore;
import androidx.lifecycle.ViewModelStoreOwner;
import androidx.room.Room;

import com.chaquo.python.PyException;
import com.chaquo.python.PyObject;
import com.chaquo.python.Python;
import com.example.myapplication.DataBase.AppDatabase;
import com.example.myapplication.DataBase.DatabaseHelper;
import com.example.myapplication.Service.FloatingWindowService;
import com.example.myapplication.Service.PhotoMonitoringService;
import com.example.myapplication.Service.RecordingService;
import com.example.myapplication.Tool.BackgroundToast;
import com.example.myapplication.Tool.DynamicDataFetcher;
import com.example.myapplication.Tool.PermissionUtils;
import com.example.myapplication.Tool.ReportGenerator;
import com.example.myapplication.Tool.ReportGeneratorHelper;
import com.example.myapplication.Tool.RetrofitClient;
import com.example.myapplication.api.AuthApi;
import com.example.myapplication.api.PartService;
import com.example.myapplication.api.ProjectApi;
import com.example.myapplication.api.TurbineApiService;
import com.example.myapplication.model.ApiResponse;
import com.example.myapplication.model.AudioEntity;
import com.example.myapplication.model.ChangePasswordRequest;
import com.example.myapplication.model.ImageEntity;
import com.example.myapplication.model.PartResponse;
import com.example.myapplication.model.Project;
import com.example.myapplication.model.SharedDataManager;
import com.example.myapplication.model.Turbine;
import com.getbase.floatingactionbutton.FloatingActionButton;
import com.google.android.material.datepicker.MaterialDatePicker;
import com.google.android.material.switchmaterial.SwitchMaterial;
import com.google.android.material.textfield.TextInputEditText;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import retrofit2.Retrofit;
// 在MainActivity类中添加以下变量


public class MainActivity extends AppCompatActivity implements ViewModelStoreOwner {
    private ViewModelStore viewModelStore = new ViewModelStore();
    private DynamicDataFetcher fetcher;
    private Spinner spinnerImageSource;
    private List<Map<String, String>> imageSources = new ArrayList<>();
    private AlertDialog reportcurrentDialog; // 添加成员变量来保存当前对话框
    private boolean haveInitalFloating = false;
    private static String Temperator = "0";
    private static String Humidity = "0";
    private static String Weather = "0";
    private TextInputEditText etWeather, etTemperature, etHumidity;
    private Button btnSaveWeather;
    private TextView tvWeatherDisplay, tvTemperatureDisplay, tvHumidityDisplay;

    @Override
    public ViewModelStore getViewModelStore() {
        return viewModelStore;
    }

    private static final int NOTIFICATION_PERMISSION_REQUEST_CODE = 102;
    private DatabaseHelper dbHelper;
    private long startTimestamp = 0;
    private long endTimestamp = 0;
    private String startDateStr = "";
    private String endDateStr = "";
    private TextView tvUser;
    private Button btnAdmin;
    // 在类变量声明部分添加
    private Button btnUploadVideos;
    private Button btnUploadVideos2;

    private FloatingActionButton floatingActionButton;
    private boolean isRecording = false;
    private MediaRecorder mediaRecorder;
    private String currentAudioPath;

    private final OkHttpClient httpClient = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)  // 连接超时
            .readTimeout(60, TimeUnit.SECONDS)     // 读取超时
            .writeTimeout(60, TimeUnit.SECONDS)    // 写入超时
            .build();
    private static final String TAG = "MainActivity";
    private static String outputPath = "report" + ".json";


    private TextView tvStatus;
    private final Handler mainHandler = new Handler(Looper.getMainLooper());
    private ReportGeneratorHelper reportGenerator;
    private Button selectTimeButton;


    private TextView startTimeText;
    private TextView endTimeText;
    private long startTime = 0;
    private long endTime = 0;

    private TextView statusText;


    private long lastPhotoId = -1;
    private boolean isMonitoring = false;
    private SwitchMaterial switchMonitor;


    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
    private AppDatabase db;
    private static final int PERMISSION_REQUEST_CODE = 100;
    private static final int PERMISSIONS_REQUEST_CODE = 109;

    private AppDatabase db2;
    private Button btnHistory;
    private Button btnFailedAudios;
    private Button btnFailedAudios2;
    private Button btnHistory2;
    private AlertDialog currentDialog;
    private AlertDialog currentDialog2;
    private static final int THUMBNAIL_SIZE = 200;
    private static final int DECODE_SAMPLE_SIZE = 4;


    private final ExecutorService executor = Executors.newFixedThreadPool(4);
    // 添加位置相关变量

    private LocationManager locationManager;
    private LocationListener locationListener;
    private Location lastKnownLocation;

    private static final int LOCATION_PERMISSION_REQUEST_CODE = 1002;
    private TextView locationText;
    private static final int AUDIO_PERMISSION_REQUEST_CODE = 1030;
    private Button btnUploadQueue;
    private Button btnStopUpload;
    private volatile boolean isUploading = false;
    private final Object uploadLock = new Object();

    private EditText etUploadInterval;
    private Button btnSetInterval;
    private Button btnStartTimedUpload;
    private Button btnStopTimedUpload;
    private Handler timedUploadHandler;
    private Runnable timedUploadRunnable;
    private static final int OVERLAY_PERMISSION_REQUEST_CODE = 1003;
    private int uploadIntervalMinutes = 0; // 默认上传间隔(分钟)
    private boolean isTimedUploadRunning = false;
    private static final int REQUEST_VIDEO_PERMISSION = 1005;
    // 在类变量声明部分添加
    private ActivityResultLauncher<Intent> videoPickerLauncher;
    private InputMethodManager inputMethodManager;
    private ActivityResultLauncher<String[]> requestPermissionLauncher;
    private static final String ACTION_UPDATE_VALUES = "com.example.myapplication.UPDATE_VALUES";
    private BroadcastReceiver updateReceiver;
    private String currentUsername;
    private String projectName = "";
    private String projectId = "";
    private String partId = "";
    private String partName = "";
    private String imgpath = "-1";
    private String password = "-1";
    private final int PERMISSION_REQUEST_StartMonitor_CODE = 99;
    private String name = "-1";
    private String turbineId = "";
    private String turbineName = "";
    private Button changepassword;
    private Map<Pair<String, String>, String> nameToIdMap;
    private String ChooseImageSource = "-1";
    private ActivityResultLauncher<Intent> overlayPermissionLauncher;
    private SharedDataManager dataManager;
    private String UserId = "-1";
    private Button btnReadReport;

    private Button btnGenerateReport;
    private ReportGenerator reportGeneratorreal;
    private Button btnClearProject;
    private static final String PREF_PROJECT = "project"; // 新增项目键名
    private AutoCompleteTextView actvProject;
    private ArrayAdapter<Project> projectAdapter;
    private List<Project> projectList = new ArrayList<>();
    private Button btnClearTurbine;
    private static final String PREF_TURBINE = "turbine"; // 新增机组键名
    private AutoCompleteTextView actvTurbine;
    private ArrayAdapter<Turbine> turbineAdapter;
    private List<Turbine> turbineList = new ArrayList<>();
    private Button btnClearPart;
    private static final String PREF_PART = "part"; // 新增部件键名
    private AutoCompleteTextView actvPart;
    private ArrayAdapter<PartResponse> partAdapter;
    private List<PartResponse> partList = new ArrayList<>();

    private SharedPreferences sharedPreferences;
    private static final String PREFS_NAME = "LoginPrefs";
    private static final String PREF_REMEMBER = "remember";
    private final String AUTH_TOKEN_KEY = "auth_token";
    private String authToken = "";
    private boolean init = false;

    @SuppressLint("UnspecifiedRegisterReceiverFlag")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initializeViews();


        sharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
        authToken = sharedPreferences.getString(AUTH_TOKEN_KEY, "");
        dbHelper = new DatabaseHelper(MainActivity.this);

        setupProjectListeners();
        // 初始化项目下拉框
        initProjectDropdown();
        initTurbineDropdown();
        initPartDropdown();
        loadProjects();
        reportGeneratorreal = new ReportGenerator(this);

        btnGenerateReport.setOnClickListener(v -> {


            String outputpath = reportGeneratorreal.generateReport();


            if (outputpath != null && !outputpath.startsWith("Error")) {
                // 获取文件夹中的所有文件
                File folder = new File(outputpath);
                if (folder.exists() && folder.isDirectory()) {
                    File[] files = folder.listFiles();
                    if (files != null && files.length > 0) {
                        // 显示文件列表对话框
                        showFileListDialog(files);
                    } else {
                        Toast.makeText(this, "文件夹为空，没有可显示的文件", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(this, "路径无效或不是文件夹", Toast.LENGTH_SHORT).show();
                }
            } else {
                // 显示错误信息
                Toast.makeText(this, "报告生成失败: " + outputpath, Toast.LENGTH_LONG).show();
            }


// 检查路径是否有效
            // 检查路径是否有效

        });
        String outputpath2 = getExternalFilesDir(null).getAbsolutePath();
        btnReadReport.setOnClickListener(v -> {
            if (outputpath2 != null && !outputpath2.startsWith("Error")) {
                // 获取文件夹中的所有文件
                File folder = new File(outputpath2);
                if (folder.exists() && folder.isDirectory()) {
                    File[] files = folder.listFiles();
                    if (files != null && files.length > 0) {
                        // 显示文件列表对话框
                        showFileListDialog(files);
                    } else {
                        Toast.makeText(this, "文件夹为空，没有可显示的文件", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(this, "路径无效或不是文件夹", Toast.LENGTH_SHORT).show();
                }
            } else {
                // 显示错误信息
                Toast.makeText(this, "报告生成失败: " + outputpath2, Toast.LENGTH_LONG).show();
            }
        });
        dataManager = SharedDataManager.getInstance();
        reportGenerator = new ReportGeneratorHelper(this);

        // 从 SharedPreferences 加载保存的天气信息
        SharedPreferences prefs = getSharedPreferences("WeatherPrefs", MODE_PRIVATE);
        Weather = prefs.getString("weather", "0");
        Temperator = prefs.getString("temperature", "0");
        Humidity = prefs.getString("humidity", "0");

        // 设置输入框的默认值
        etWeather.setText(Weather);
        etTemperature.setText(Temperator);
        etHumidity.setText(Humidity);

        // 更新显示
        updateWeatherDisplay();

        // 设置保存按钮点击事件
        btnSaveWeather.setOnClickListener(v -> saveWeatherInfo());
        initializeDatabase();
        initializeReceivers();
        initializePermissionLaunchers();
        initialUser();
        requestInitialPermissions();
        setupButtonListeners();
        setupTimedUpload();
        if (!haveInitalFloating)
            initFloatingActionButton();

        dataManager.setToken(authToken);

        name = sharedPreferences.getString("name", "-1");
        UserId = sharedPreferences.getString("userid", "-1");
        dataManager.setUser(getCurrentUser());
        initApp();

        changepassword.setOnClickListener(v -> {
            showChangePasswordDialog(currentUsername);
        });

// 使用 DynamicDataFetcher 替代 CommonImageSourceFetcher，指定数据类型为 "image_sources"
        fetcher = new DynamicDataFetcher(authToken, this, "image_sources");
        loadImageSources();

// 设置下拉框选择监听
        spinnerImageSource.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                if (position >= 0 && position < imageSources.size()) {
                    Map<String, String> selectedItem = imageSources.get(position);
                    String value = selectedItem.get("value");

                    String key = selectedItem.get("key");
                    ChooseImageSource = key;
                    dataManager.setChooseImageSource(ChooseImageSource);
                    Toast.makeText(MainActivity.this,
                            "选择了: " + value + " (Key: " + key + ")",
                            Toast.LENGTH_SHORT).show();

                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                // 未选择任何项
            }
        });


    }

    private void setupProjectListeners() {
        // 清空项目按钮点击事件
        btnClearProject.setOnClickListener(v -> clearProject());
        btnClearTurbine.setOnClickListener(v -> clearTurbine());
        btnClearPart.setOnClickListener(v -> clearPart());
    }

    private void clearProject() {
        projectId = "";
        projectName = "";
        sharedPreferences.edit().putString(PREF_PROJECT, "").apply();
        dataManager.setProjectId("");
        actvProject.setText("");
        loadProjects();
        projectAdapter.getFilter().filter("");
        clearTurbine();
        clearPart();
    }

    private void clearTurbine() {
        turbineId = "";
        turbineName = "";
        sharedPreferences.edit().putString(PREF_TURBINE, "").apply();
        dataManager.setTurbineId("");
        dataManager.setTurbineName("");
        actvTurbine.setText("");
        loadTurbines();
        turbineAdapter.getFilter().filter("");
        clearPart();
    }

    private void clearPart() {
        partId = "";
        partName = "";
        sharedPreferences.edit().putString(PREF_PART, "").apply();
        dataManager.setPartId("");
        dataManager.setPartName("");
        actvPart.setText("");
        loadParts();
        partAdapter.getFilter().filter("");
    }

    private void loadProjectPreferences(List<Project> projects) {
        if (init) {
            return;
        }
        init = true;
        boolean remember = sharedPreferences.getBoolean(PREF_REMEMBER, false);
        if (remember) {
//            项目
            String savedProject = sharedPreferences.getString(PREF_PROJECT, "");

            if (!savedProject.isEmpty()) {
                try {
                    int lastBracketIndex = savedProject.lastIndexOf("(");
                    int closingBracketIndex = savedProject.lastIndexOf(")");

                    if (lastBracketIndex != -1 && closingBracketIndex != -1 && closingBracketIndex > lastBracketIndex) {
                        projectName = savedProject.substring(0, lastBracketIndex).trim();
                        projectId = savedProject.substring(lastBracketIndex + 1, closingBracketIndex).trim();
                        dataManager.setProjectId(projectId);
                        actvProject.setText(projectName);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
//            机组
            String savedTurbine = sharedPreferences.getString(PREF_TURBINE, "");

            if (!savedTurbine.isEmpty()) {
                try {
                    int lastBracketIndex = savedTurbine.lastIndexOf("(");
                    int closingBracketIndex = savedTurbine.lastIndexOf(")");

                    if (lastBracketIndex != -1 && closingBracketIndex != -1 && closingBracketIndex > lastBracketIndex) {
                        turbineName = savedTurbine.substring(0, lastBracketIndex).trim();
                        turbineId = savedTurbine.substring(lastBracketIndex + 1, closingBracketIndex).trim();
                        dataManager.setTurbineId(turbineId);
                        dataManager.setTurbineName(turbineName);
                        actvTurbine.setText(turbineName);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
//            部件
            String savedPart = sharedPreferences.getString(PREF_PART, "");

            if (!savedPart.isEmpty()) {
                try {
                    int lastBracketIndex = savedPart.lastIndexOf("(");
                    int closingBracketIndex = savedPart.lastIndexOf(")");

                    if (lastBracketIndex != -1 && closingBracketIndex != -1 && closingBracketIndex > lastBracketIndex) {
                        partName = savedPart.substring(0, lastBracketIndex).trim();
                        partId = savedPart.substring(lastBracketIndex + 1, closingBracketIndex).trim();
                        dataManager.setPartId(partId);
                        dataManager.setPartName(partName);
                        actvPart.setText(partName);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void loadProjects() {
        try {
            // 2. 初始化Retrofit
            Retrofit retrofit = RetrofitClient.getClient(authToken);
            // 3. 创建API服务
            ProjectApi projectApi = retrofit.create(ProjectApi.class);
            // 4. 执行网络请求
            executeProjectRequest(projectApi);

        } catch (Exception e) {
            showErrorOnUI("初始化失败", getErrorMessage(e));
            logErrorToFile(e);
        }
    }

    private void loadTurbines() {
        if (projectId.isEmpty()) {
            return;
        }
        try {
            // 2. 初始化Retrofit
            Retrofit retrofit = RetrofitClient.getClient(authToken);
            // 3. 创建API服务
            TurbineApiService turbine = retrofit.create(TurbineApiService.class);
            // 4. 执行网络请求
            executeTurbineRequest(turbine);

        } catch (Exception e) {
            showErrorOnUI("初始化失败", getErrorMessage(e));
            logErrorToFile(e);
        }
    }

    private void loadParts() {
        if (projectId.isEmpty() || turbineId.isEmpty()) {
            return;
        }
        try {
            // 2. 初始化Retrofit
            Retrofit retrofit = RetrofitClient.getClient(authToken);
            // 3. 创建API服务
            PartService part = retrofit.create(PartService.class);
            // 4. 执行网络请求
            executePartRequest(part);

        } catch (Exception e) {
            showErrorOnUI("初始化失败", getErrorMessage(e));
            logErrorToFile(e);
        }
    }

    private void initProjectDropdown() {
        projectAdapter = new ArrayAdapter<Project>(this,
                R.layout.custom_dropdown_item,
                projectList) {
            @NonNull
            @Override
            public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                TextView textView = view.findViewById(android.R.id.text1);
                Project project = getItem(position);
                if (project != null) {
                    textView.setText(project.getProjectName());
                    textView.setSingleLine(false);
                    textView.setMaxLines(3);
                    textView.setEllipsize(null);
                }
                return view;
            }

            @Override
            public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
                return getView(position, convertView, parent);
            }

            @Override
            public Filter getFilter() {
                return new Filter() {
                    @Override
                    protected FilterResults performFiltering(CharSequence constraint) {
                        FilterResults results = new FilterResults();
                        List<Project> filteredList = new ArrayList<>();

                        if (constraint != null && constraint.length() > 0) {
                            String filterPattern = constraint.toString().toLowerCase().trim();
                            filteredList = dbHelper.searchProjects(filterPattern);
                        } else {
                            filteredList.addAll(projectList);
                        }

                        results.values = filteredList;
                        results.count = filteredList.size();
                        return results;
                    }

                    @Override
                    protected void publishResults(CharSequence constraint, FilterResults results) {
                        clear();
                        if (results.values != null) {
                            addAll((List<Project>) results.values);
                        }
                        notifyDataSetChanged();
                    }
                };
            }
        };

        actvProject.setAdapter(projectAdapter);
        actvProject.setThreshold(0);
        actvProject.setDropDownBackgroundResource(android.R.color.white);

        actvProject.setOnItemClickListener((parent, view, position, id) -> {
            Object item = parent.getItemAtPosition(position);
            if (item instanceof Project) {
                Project selectedProject = (Project) item;
                projectName = selectedProject.getProjectName();
                projectId = selectedProject.getProjectId();
                actvProject.setText(projectName);
                sharedPreferences.edit().putString(PREF_PROJECT, projectName + "(" + projectId + ")").apply();
                dataManager.setProjectId(projectId);
                loadTurbines();
            } else {
                Log.e("TYPE_ERROR", "Expected Project but got: " + item.getClass());
                Toast.makeText(this, "数据格式错误", Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void initTurbineDropdown() {
        turbineAdapter = new ArrayAdapter<>(this,
                R.layout.custom_dropdown_item,
                turbineList) {
            @NonNull
            @Override
            public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                TextView textView = view.findViewById(android.R.id.text1);
                Turbine turbine = getItem(position);
                if (turbine != null) {
                    textView.setText(turbine.getTurbineName() + ")");
                    textView.setSingleLine(false);
                    textView.setMaxLines(3);
                    textView.setEllipsize(null);
                }
                return view;
            }

            @Override
            public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
                return getView(position, convertView, parent);
            }

            @Override
            public Filter getFilter() {
                return new Filter() {
                    @Override
                    protected FilterResults performFiltering(CharSequence constraint) {
                        FilterResults results = new FilterResults();
                        List<Turbine> filteredList = new ArrayList<>();

                        if (constraint != null && constraint.length() > 0) {
                            String filterPattern = constraint.toString().toLowerCase().trim();
                            filteredList = dbHelper.searchTurbines(filterPattern);
                        } else {
                            filteredList.addAll(turbineList);
                        }

                        results.values = filteredList;
                        results.count = filteredList.size();
                        return results;
                    }

                    @Override
                    protected void publishResults(CharSequence constraint, FilterResults results) {
                        clear();
                        if (results.values != null) {
                            addAll((List<Turbine>) results.values);
                        }
                        notifyDataSetChanged();
                    }
                };
            }
        };

        actvTurbine.setAdapter(turbineAdapter);
        actvTurbine.setThreshold(0);
        actvTurbine.setDropDownBackgroundResource(android.R.color.white);

        actvTurbine.setOnItemClickListener((parent, view, position, id) -> {
            Object item = parent.getItemAtPosition(position);
            if (item instanceof Turbine) {
                Turbine selectedTurbine = (Turbine) item;
                turbineName = selectedTurbine.getTurbineName();
                turbineId = selectedTurbine.getTurbineId();
                actvTurbine.setText(turbineName);
                sharedPreferences.edit().putString(PREF_TURBINE, turbineName + "(" + turbineId + ")").apply();
                dataManager.setTurbineId(turbineId);
                dataManager.setTurbineName(turbineName);
                loadParts();
            } else {
                Log.e("TYPE_ERROR", "Expected Turbine but got: " + item.getClass());
                Toast.makeText(this, "数据格式错误", Toast.LENGTH_SHORT).show();
            }
        });
    }


    private void initPartDropdown() {
        partAdapter = new ArrayAdapter<PartResponse>(this,
                R.layout.custom_dropdown_item,
                partList) {
            @NonNull
            @Override
            public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                TextView textView = view.findViewById(android.R.id.text1);
                PartResponse part = getItem(position);
                if (part != null) {
                    textView.setText(part.getPartName());
                    textView.setSingleLine(false);
                    textView.setMaxLines(3);
                    textView.setEllipsize(null);
                }
                return view;
            }

            @Override
            public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
                return getView(position, convertView, parent);
            }

            @Override
            public Filter getFilter() {
                return new Filter() {
                    @Override
                    protected FilterResults performFiltering(CharSequence constraint) {
                        FilterResults results = new FilterResults();
                        List<PartResponse> filteredList = new ArrayList<>();

                        if (constraint != null && constraint.length() > 0) {
                            String filterPattern = constraint.toString().toLowerCase().trim();
                            filteredList = dbHelper.searchParts(filterPattern);
                        } else {
                            filteredList.addAll(partList);
                        }

                        results.values = filteredList;
                        results.count = filteredList.size();
                        return results;
                    }

                    @Override
                    protected void publishResults(CharSequence constraint, FilterResults results) {
                        clear();
                        if (results.values != null) {
                            addAll((List<PartResponse>) results.values);
                        }
                        notifyDataSetChanged();
                    }
                };
            }
        };

        actvPart.setAdapter(partAdapter);
        actvPart.setThreshold(0);
        actvPart.setDropDownBackgroundResource(android.R.color.white);

        actvPart.setOnItemClickListener((parent, view, position, id) -> {
            Object item = parent.getItemAtPosition(position);
            if (item instanceof PartResponse) {
                PartResponse selectedPart = (PartResponse) item;
                partName = selectedPart.getPartName();
                partId = selectedPart.getPartId();
                actvPart.setText(partName);
                sharedPreferences.edit().putString(PREF_PART, partName + "(" + partId + ")").apply();
                dataManager.setPartId(partId);
                dataManager.setPartName(partName);
            } else {
                Log.e("TYPE_ERROR", "Expected Part but got: " + item.getClass());
                Toast.makeText(this, "数据格式错误", Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void executeProjectRequest(ProjectApi projectApi) {
        retrofit2.Call<ApiResponse<List<Project>>> call = projectApi.getMyProjectList();

        call.enqueue(new retrofit2.Callback<>() {
            @Override
            public void onResponse(retrofit2.Call<ApiResponse<List<Project>>> call, retrofit2.Response<ApiResponse<List<Project>>> response) {
                if (response.isSuccessful() && response.body() != null) {
                    handleSuccessProjectResponse(response.body().getData());
                    loadProjectPreferences(response.body().getData());
                } else {
                    handleApiError(response);
                    loadCachedProjects();
                }
            }

            @Override
            public void onFailure(retrofit2.Call<ApiResponse<List<Project>>> call, Throwable t) {
                handleNetworkError(t);
                loadCachedProjects();
            }
        });
    }

    private void executeTurbineRequest(TurbineApiService projectApi) {
        retrofit2.Call<ApiResponse<List<Turbine>>> call = projectApi.getTurbineList(projectId);

        call.enqueue(new retrofit2.Callback<>() {
            @Override
            public void onResponse(retrofit2.Call<ApiResponse<List<Turbine>>> call, retrofit2.Response<ApiResponse<List<Turbine>>> response) {
                if (response.isSuccessful() && response.body() != null) {
                    handleSuccessTurbineResponse(response.body().getData());
                } else {
                    handleApiError(response);
                    loadCachedTurbines();
                }
            }

            @Override
            public void onFailure(retrofit2.Call<ApiResponse<List<Turbine>>> call, Throwable t) {
                handleNetworkError(t);
                loadCachedTurbines();
            }
        });
    }

    private void executePartRequest(PartService partApi) {
        retrofit2.Call<ApiResponse<List<PartResponse>>> call = partApi.getPartList(projectId, turbineId, null, null, null, null);

        call.enqueue(new retrofit2.Callback<>() {
            @Override
            public void onResponse(retrofit2.Call<ApiResponse<List<PartResponse>>> call, retrofit2.Response<ApiResponse<List<PartResponse>>> response) {
                if (response.isSuccessful() && response.body() != null) {
                    handleSuccessPartResponse(response.body().getData());
                } else {
                    handleApiError(response);
                    loadCachedParts();
                }
            }

            @Override
            public void onFailure(retrofit2.Call<ApiResponse<List<PartResponse>>> call, Throwable t) {
                handleNetworkError(t);
                loadCachedParts();
            }
        });
    }

    // === 错误处理方法 ===
    private void handleSuccessProjectResponse(List<Project> projects) {
        runOnUiThread(() -> {
            try {
                dbHelper.saveProjects(projects);
                projectList.clear();
                projectList.addAll(projects);
                projectAdapter.notifyDataSetChanged();
            } catch (Exception e) {
                showErrorOnUI("数据处理错误", e.getMessage());
            }
        });
    }

    private void handleSuccessTurbineResponse(List<Turbine> turbines) {
        runOnUiThread(() -> {
            try {
                dbHelper.saveTurbines(turbines);
                turbineList.clear();
                turbineList.addAll(turbines);
                turbineAdapter.notifyDataSetChanged();
            } catch (Exception e) {
                showErrorOnUI("数据处理错误", e.getMessage());
            }
        });
    }

    private void handleSuccessPartResponse(List<PartResponse> parts) {
        runOnUiThread(() -> {
            try {
                dbHelper.saveParts(parts);
                partList.clear();
                partList.addAll(parts);
                partAdapter.notifyDataSetChanged();
            } catch (Exception e) {
                showErrorOnUI("数据处理错误", e.getMessage());
            }
        });
    }

    private void handleApiError(retrofit2.Response<?> response) {
        String errorMsg = "服务器响应错误: " + response.code();
        try {
            if (response.errorBody() != null) {
                errorMsg += "\n" + response.errorBody().string();
            }
        } catch (IOException e) {
            errorMsg += "\n无法读取错误详情";
        }

        showErrorOnUI("API请求失败", errorMsg);
    }

    private void handleNetworkError(Throwable t) {
        String errorMsg = "网络错误: " + t.getMessage();
        if (t instanceof SocketTimeoutException) {
            errorMsg = "连接超时，请检查网络";
        } else if (t instanceof UnknownHostException) {
            errorMsg = "无法解析主机，请检查URL";
        }

        showErrorOnUI("网络连接失败", errorMsg);
    }

    private void loadCachedProjects() {
        new Thread(() -> {
            List<Project> cachedProjects = dbHelper.getAllProjects();
            runOnUiThread(() -> {
                projectList.clear();
                projectList.addAll(cachedProjects);
                projectAdapter.notifyDataSetChanged();
                Toast.makeText(this, "已加载本地缓存项目数据", Toast.LENGTH_LONG).show();
            });
        }).start();
    }

    private void loadCachedTurbines() {
        new Thread(() -> {
            List<Turbine> cachedTurbines = dbHelper.getAllTurbines();
            runOnUiThread(() -> {
                turbineList.clear();
                turbineList.addAll(cachedTurbines);
                turbineAdapter.notifyDataSetChanged();
                Toast.makeText(this, "已加载本地缓存机组数据", Toast.LENGTH_LONG).show();
            });
        }).start();
    }

    private void loadCachedParts() {
        new Thread(() -> {
            List<PartResponse> cachedParts = dbHelper.getAllParts();
            runOnUiThread(() -> {
                partList.clear();
                partList.addAll(cachedParts);
                partAdapter.notifyDataSetChanged();
                Toast.makeText(this, "已加载本地缓存部件数据", Toast.LENGTH_LONG).show();
            });
        }).start();
    }

    // === 工具方法 ===
    private void showErrorOnUI(String title, String message) {
        runOnUiThread(() -> {
            // 在界面底部显示错误面板
            ViewGroup rootView = findViewById(android.R.id.content);
            LinearLayout errorPanel = new LinearLayout(this);
            errorPanel.setOrientation(LinearLayout.VERTICAL);
            errorPanel.setBackgroundColor(0x33FF0000);
            errorPanel.setPadding(32, 16, 32, 16);

            TextView tvError = new TextView(this);
            tvError.setTextColor(Color.RED);
            tvError.setText(title);

            TextView tvMsg = new TextView(this);
            tvMsg.setText(message);

            errorPanel.addView(tvError);
            errorPanel.addView(tvMsg);
            rootView.addView(errorPanel);

            // 5秒后自动消失
            new Handler().postDelayed(() -> rootView.removeView(errorPanel), 5000);
        });
    }

    private void copyToClipboard(String text) {
        ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
        clipboard.setPrimaryClip(ClipData.newPlainText("错误定义", text));
        Toast.makeText(this, "定义已复制", Toast.LENGTH_SHORT).show();
    }

    private String getErrorMessage(Exception e) {
        if (e instanceof IllegalArgumentException) {
            return "参数错误: " + e.getMessage();
        } else if (e instanceof NullPointerException) {
            return "空指针异常: " + e.getMessage();
        } else {
            return "未知错误: " + e.getClass().getSimpleName();
        }
    }

    private void logErrorToFile(Exception e) {
        String log = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) +
                "\nError: " + e.getClass().getName() +
                "\nMessage: " + e.getMessage() +
                "\nStack Trace:\n" + Log.getStackTraceString(e);

        try {
            File file = new File(getExternalFilesDir(null), "error_log.txt");
            FileWriter writer = new FileWriter(file, true);
            writer.append(log).append("\n\n");
            writer.close();
        } catch (IOException ioException) {
            Log.e("FileLog", "无法写入错误日志", ioException);
        }
    }

    // 在Activity中
    private void showFileListDialog(File[] files) {
        // 构建文件名列表和文件对象列表
        List<String> fileNames = new ArrayList<>();
        final List<File> fileList = new ArrayList<>(); // 用于存储文件对象，保持与显示列表一致

        for (File file : files) {
            if (file.isFile()) { // 只显示文件，不显示子文件夹
                fileNames.add(file.getName());
                fileList.add(file);
            }
        }

        // 创建对话框
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("文件操作");

        // 设置对话框选项
        String[] dialogItems = {"查看文件", "删除选中文件", "删除所有文件"};
        builder.setItems(dialogItems, (dialog, which) -> {
            switch (which) {
                case 0: // 查看文件
                    showFileSelectionDialog(fileList, false);
                    break;
                case 1: // 删除选中文件
                    showMultiSelectDeleteDialog(fileList);
                    break;
                case 2: // 删除所有文件
                    showDeleteAllConfirmationDialog(fileList);
                    break;
            }
        });

        builder.setNegativeButton("取消", null);
        builder.show();
    }

    // 显示文件选择对话框（用于查看或单选删除）
    private void showFileSelectionDialog(List<File> fileList, boolean isDeleteMode) {
        CharSequence[] items = new CharSequence[fileList.size()];
        for (int i = 0; i < fileList.size(); i++) {
            items[i] = fileList.get(i).getName();
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(isDeleteMode ? "选择要删除的文件" : "选择要查看的文件");

        builder.setItems(items, (dialog, which) -> {
            File selectedFile = fileList.get(which);
            if (isDeleteMode) {
                showDeleteConfirmationDialog(selectedFile);
            } else {
                openFile(selectedFile.getAbsolutePath());
            }
        });

        builder.setNegativeButton("取消", null);
        builder.show();
    }

    // 显示多选删除对话框
    private void showMultiSelectDeleteDialog(List<File> fileList) {
        if (fileList.isEmpty()) {
            Toast.makeText(this, "没有可删除的文件", Toast.LENGTH_SHORT).show();
            return;
        }

        CharSequence[] items = new CharSequence[fileList.size()];
        final boolean[] checkedItems = new boolean[fileList.size()];

        for (int i = 0; i < fileList.size(); i++) {
            items[i] = fileList.get(i).getName();
            checkedItems[i] = false; // 初始状态未选中
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("选择要删除的文件");

        builder.setMultiChoiceItems(items, checkedItems, (dialog, which, isChecked) -> {
            checkedItems[which] = isChecked;
        });

        builder.setPositiveButton("删除选中", (dialog, which) -> {
            int deleteCount = 0;
            for (int i = 0; i < checkedItems.length; i++) {
                if (checkedItems[i]) {
                    File fileToDelete = fileList.get(i);
                    if (fileToDelete.delete()) {
                        deleteCount++;
                    }
                }
            }
            Toast.makeText(this, "已删除 " + deleteCount + " 个文件", Toast.LENGTH_SHORT).show();
            // 刷新文件列表
            refreshFileList();
        });

        builder.setNegativeButton("取消", null);
        builder.show();
    }

    // 显示删除所有文件确认对话框
    private void showDeleteAllConfirmationDialog(List<File> fileList) {
        if (fileList.isEmpty()) {
            Toast.makeText(this, "没有可删除的文件", Toast.LENGTH_SHORT).show();
            return;
        }

        new AlertDialog.Builder(this)
                .setTitle("确认删除所有文件")
                .setMessage("确定要删除所有 " + fileList.size() + " 个文件吗？此操作不可恢复！")
                .setPositiveButton("删除全部", (dialog, which) -> {
                    int deleteCount = 0;
                    for (File file : fileList) {
                        if (file.delete()) {
                            deleteCount++;
                        }
                    }
                    Toast.makeText(this, "已删除 " + deleteCount + " 个文件", Toast.LENGTH_SHORT).show();
                    // 刷新文件列表
                    refreshFileList();
                })
                .setNegativeButton("取消", null)
                .show();
    }

    // 显示单个文件删除确认对话框
    private void showDeleteConfirmationDialog(File fileToDelete) {
        new AlertDialog.Builder(this)
                .setTitle("确认删除")
                .setMessage("确定要删除 " + fileToDelete.getName() + " 吗？")
                .setPositiveButton("删除", (dialog, which) -> {
                    if (fileToDelete.delete()) {
                        Toast.makeText(this, "文件已删除", Toast.LENGTH_SHORT).show();
                        // 刷新文件列表
                        refreshFileList();
                    } else {
                        Toast.makeText(this, "删除失败", Toast.LENGTH_SHORT).show();
                    }
                })
                .setNegativeButton("取消", null)
                .show();
    }

    // 刷新文件列表
    private void refreshFileList() {
        // 重新获取文件列表并刷新对话框
        File directory = getFilesDir(); // 或者您原来的文件目录
        File[] files = directory.listFiles();
        if (files != null) {
            showFileListDialog(files);
        }
    }


    private void openFile(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show();
            return;
        }

        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri uri = FileProvider.getUriForFile(this, getPackageName() + ".provider", file);

        // 根据文件类型设置 MIME 类型
        String mimeType = getMimeType(file.getName());
        if (mimeType == null) {
            Toast.makeText(this, "无法识别文件类型", Toast.LENGTH_SHORT).show();
            return;
        }

        intent.setDataAndType(uri, mimeType);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

        try {
            startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this, "无法打开文件，请安装支持的应用程序", Toast.LENGTH_SHORT).show();
        }
    }

    // 根据文件扩展名获取 MIME 类型

    private void saveWeatherInfo() {
        Weather = etWeather.getText().toString().trim();
        Temperator = etTemperature.getText().toString().trim();
        Humidity = etHumidity.getText().toString().trim();

        // 简单验证（可选）
        if (Weather.isEmpty()) {
            Toast.makeText(this, "请输入天气", Toast.LENGTH_SHORT).show();
            return;
        }

        // 保存到 SharedPreferences
        SharedPreferences prefs = getSharedPreferences("WeatherPrefs", MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString("weather", Weather);
        editor.putString("temperature", Temperator);
        editor.putString("humidity", Humidity);
        editor.apply();

        // 更新显示
        updateWeatherDisplay();

        // 提示保存成功
        Toast.makeText(this, "天气信息已保存", Toast.LENGTH_SHORT).show();
    }

    private void updateWeatherDisplay() {
        tvWeatherDisplay.setText("天气: " + (Weather.isEmpty() ? "未设置" : Weather));
        tvTemperatureDisplay.setText("温度: " + (Temperator.isEmpty() ? "未设置" : Temperator + "℃"));
        tvHumidityDisplay.setText("湿度: " + (Humidity.isEmpty() ? "未设置" : Humidity + "%"));
    }

    private void startMonitoring() {
        String[] requiredPermissions = {
                Manifest.permission.CAMERA,
                Manifest.permission.FOREGROUND_SERVICE_CAMERA,
                Manifest.permission.READ_EXTERNAL_STORAGE
        };

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
                ContextCompat.checkSelfPermission(this, Manifest.permission.FOREGROUND_SERVICE_CAMERA) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(this, requiredPermissions, PERMISSION_REQUEST_StartMonitor_CODE);
        } else {
            Intent serviceIntent = new Intent(this, PhotoMonitoringService.class);
            serviceIntent.putExtra("command", "start_monitoring");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startForegroundService(serviceIntent);
                statusText.setText("当前状态：正在监听相册变化");
                switchMonitor.setChecked(true);
            } else {
                startService(serviceIntent);
                statusText.setText("当前状态：正在监听相册变化");
                switchMonitor.setChecked(true);
            }
        }
    }

    private void loadImageSources() {
        fetcher.fetchDynamicDataAsync(new DynamicDataFetcher.DynamicDataCallback() {
            @Override
            public void onSuccess(List<Map<String, String>> sources) {
                runOnUiThread(() -> {

                    // 过滤掉null值
                    imageSources = new ArrayList<>();
                    for (Map<String, String> item : sources) {
                        if (item != null && !item.isEmpty()) {
                            // 获取第一个也是唯一的entry（因为每个map只有一个键值对）
                            Map.Entry<String, String> entry = item.entrySet().iterator().next();
                            String key = entry.getKey();
                            String value = entry.getValue();

                            if (value != null) {
                                // 创建一个新的map，统一结构为{"key":key, "value":value}
                                Map<String, String> normalizedItem = new HashMap<>();
                                normalizedItem.put("key", key);
                                normalizedItem.put("value", value);
                                imageSources.add(normalizedItem);
                            }
                        }
                    }

                    if (imageSources.isEmpty()) {
                        showToast("图像数据为空");
                    } else {
                        updateSpinner(imageSources);
                    }
                });
            }

            @Override
            public void onFailure(Throwable t) {
                runOnUiThread(() -> {
                    Toast.makeText(MainActivity.this,
                            "加载失败: " + t.getMessage(),
                            Toast.LENGTH_SHORT).show();
                });
            }
        });
    }

    private void updateSpinner(List<Map<String, String>> sources) {
        // 提取显示文本并确保不为null
        List<String> displayValues = new ArrayList<>();
        for (Map<String, String> item : sources) {
            if (item != null && item.get("value") != null) {
                displayValues.add(item.get("value"));
            }
        }

        // 确保列表不为空
        if (displayValues.isEmpty()) {
            displayValues.add("没有可用的选项");
        }

        // 创建适配器
        ArrayAdapter<String> adapter = new ArrayAdapter<>(
                this,
                android.R.layout.simple_spinner_item,
                displayValues
        );
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        // 设置适配器
        spinnerImageSource.setAdapter(adapter);
    }

    private void showChangePasswordDialog(String username) {
        hideKeyboard();

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("请修改密码");

        View view = getLayoutInflater().inflate(R.layout.dialog_change_password, null);
        EditText etOldPassword = view.findViewById(R.id.etOldPassword);
        EditText etNewPassword = view.findViewById(R.id.etNewPassword);
        EditText etConfirmPassword = view.findViewById(R.id.etConfirmPassword);

        builder.setView(view);
        builder.setPositiveButton("确认", (dialog, which) -> {
            String oldPassword = etOldPassword.getText().toString().trim();
            String newPassword = etNewPassword.getText().toString().trim();
            String confirmPassword = etConfirmPassword.getText().toString().trim();

            if (newPassword.equals(confirmPassword)) {
                changePassword(username, oldPassword, newPassword);
            } else {
                Toast.makeText(this, "新密码与确认密码不匹配", Toast.LENGTH_SHORT).show();
            }
        });
        builder.setNegativeButton("取消", null);
        builder.setCancelable(false);
        builder.show();
    }

    private String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] messageDigest = md.digest(input.getBytes());

            StringBuilder hexString = new StringBuilder();
            for (byte b : messageDigest) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    private String encryptPassword(String username, String password) {
        try {
            // 1. 对账号做MD5计算
            String md5Hash = md5(username);

            // 2. 取8-24位作为密钥
            String key = md5Hash.substring(8, 24); // 8-24位（索引从0开始）
            Log.e("key:", key);
            // 3. AES加密
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // PKCS5Padding等同于PKCS7Padding在Java中
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            byte[] encryptedBytes = cipher.doFinal(password.getBytes());
            return Base64.encodeToString(encryptedBytes, Base64.DEFAULT).trim();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    private void changePassword(String username, String oldPassword, String newPassword) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> {
            try {
                // 加密旧密码和新密码
                String encryptedOldPassword = encryptPassword(username, oldPassword);
                String encryptedNewPassword = encryptPassword(username, newPassword);

                // 创建修改密码请求体
                ChangePasswordRequest request = new ChangePasswordRequest(
                        username,
                        encryptedNewPassword,
                        encryptedOldPassword
                );


                // 初始化Retrofit
                Retrofit retrofit = RetrofitClient.getClient(authToken);

                // 创建API服务
                AuthApi authApi = retrofit.create(AuthApi.class);

                // 执行修改密码请求
                retrofit2.Call<ApiResponse<Void>> call = authApi.modifyPassword(request);
                retrofit2.Response<ApiResponse<Void>> response = call.execute();

                runOnUiThread(() -> {
                    if (response.isSuccessful() && response.body() != null) {
                        if (response.body().isSuccess()) {
                            Toast.makeText(this, "密码修改成功，请重新登录", Toast.LENGTH_SHORT).show();
                            dbHelper.deleteUser(currentUsername);
                        } else {
                            Toast.makeText(this, "密码修改失败: " + response.body().toString(), Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        String errorMsg = "修改密码失败: ";
                        if (response.errorBody() != null) {
                            try {
                                errorMsg += response.errorBody().string();
                            } catch (IOException e) {
                                errorMsg += "无法读取错误详情";
                            }
                        }
                        Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show();
                    }
                });
            } catch (Exception e) {
                runOnUiThread(() ->
                        Toast.makeText(this, "修改密码出错: " + e.getMessage(), Toast.LENGTH_SHORT).show());
            }
        });
    }


    private void generateReportJson(String inputpath, List<ImageEntity> imageDataList, String outputPath, String starttime, String endtime) {
        String templateContent;
        File outputFile = new File(this.getExternalFilesDir(null), outputPath);
        if (!outputFile.getParentFile().exists()) {
            outputFile.getParentFile().mkdirs();
        }
        Map<String, List<ImageEntity>> imagesByDay = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
        for (ImageEntity image : imageDataList) {
            String day = sdf.format(new Date(image.time));
            if (!imagesByDay.containsKey(day)) {
                imagesByDay.put(day, new ArrayList<>());
            }
            imagesByDay.get(day).add(image);
        }
        Set<String> unitSet = new HashSet<>();
        for (ImageEntity image : imageDataList) {
            if (image.partName != null) {
                unitSet.add(image.partName);
            }
        }
        List<String> unitList = new ArrayList<>(unitSet);
        int n = unitList.size();
        for (Map.Entry<String, List<ImageEntity>> dayEntry : imagesByDay.entrySet()) {
            String day = dayEntry.getKey();
            List<ImageEntity> dayImages = dayEntry.getValue();

            for (int i = 0; i < n; i++) {

                String partName = unitList.get(i);

                List<ImageEntity> unitImages = new ArrayList<>();
                for (ImageEntity image : dayImages) {
                    if (partName.equals(image.partName)) {
                        unitImages.add(image);
                    }
                }
                if (unitImages.isEmpty()) {
                    continue;
                }
                List<ReportGeneratorHelper.ImageData> imageAndResistanceList = new ArrayList<>();
                for (ImageEntity image : unitImages) {
                    imageAndResistanceList.add(new ReportGeneratorHelper.ImageData(image.path, "0.6"));
                }
                ImageEntity firstImage = unitImages.get(0);
                String weather = firstImage.weather != null ? firstImage.weather : "0";
                String temperature = firstImage.temperature != null ? firstImage.temperature : "0";
                String humidity = firstImage.humidity != null ? firstImage.humidity : "0";
                if (i == 0) {
                    templateContent = readJsonFromAssets(this, inputpath);
                } else {
                    templateContent = null;
                }
                reportGenerator.generateReport(
                        templateContent,
                        outputFile.getAbsolutePath(),
                        "#" + partName,
                        day,
                        imageAndResistanceList,
                        weather,
                        temperature,
                        humidity,
                        starttime,
                        endtime,
                        new ReportGeneratorHelper.ReportGenerationCallback() {
                            @Override
                            public void onSuccess(String outputPath) {
                                runOnUiThread(() -> {
                                    showToast("Json写入成功");
                                });
                            }

                            @Override
                            public void onError(String errorMessage) {
                                runOnUiThread(() -> {
                                    showErrorDialog("Json写入失败", errorMessage);
                                });
                                Log.e("生成失败", errorMessage);
                            }
                        }
                );

            }
            // 在后台线程执行转换
            new Thread(() -> {
                try {
                    // 转换文件
                    File inputFile = new File(this.getExternalFilesDir(null), outputPath);

                    String outputPath2 = "output" + day + ".docx";
                    File outputFile2 = convertJsonToDocx(this, inputFile, outputPath2);

                    // 更新UI必须在主线程
                    mainHandler.post(() -> {
                        updateStatus("转换完成！");
                        showReportsList("output", ".docx");
                    });
                } catch (Exception e) {
                    Log.e(TAG, "Conversion failed", e);
                    mainHandler.post(() -> {
                        updateStatus("转换失败");
                        showToast("转换失败: " + e.getMessage());
                    });
                }
            }).start();
        }
    }


    // 分享文件方法


    // 删除文件方法

    // 添加方法列出所有生成的报告
    private List<File> getGeneratedReports(String start, String end) {
        File dir = this.getExternalFilesDir(null);
        File[] files = dir.listFiles((d, name) -> (name.startsWith(start) && name.endsWith(end)));

        if (files == null) {
            return Collections.emptyList();
        }

        List<File> fileList = Arrays.asList(files);

        // 按日期从大到小排序
        fileList.sort((f1, f2) -> {
            // 从文件名中提取日期部分
            String dateStr1 = f1.getName().substring(start.length(), start.length() + 10);
            String dateStr2 = f2.getName().substring(start.length(), start.length() + 10);
            // 比较日期，返回逆序结果实现从大到小排序
            return dateStr2.compareTo(dateStr1);
        });

        return fileList;
    }

    // 显示报告列表对话框


    private void showReportsList(String start, String end) {
        if (reportcurrentDialog != null && reportcurrentDialog.isShowing()) {
            reportcurrentDialog.dismiss();
        }
        List<File> reports = getGeneratedReports(start, end);

        if (reports.isEmpty()) {
            Toast.makeText(this, "没有找到生成的报告", Toast.LENGTH_SHORT).show();
            if (reportcurrentDialog != null && reportcurrentDialog.isShowing()) {
                reportcurrentDialog.dismiss();
            }
            return;
        }

        // 创建自定义对话框
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        LayoutInflater inflater = getLayoutInflater();
        View dialogView = inflater.inflate(R.layout.dialog_report_list, null);
        builder.setView(dialogView);

        // 初始化视图
        ListView listView = dialogView.findViewById(R.id.report_list);
        Button btnDeleteSelected = dialogView.findViewById(R.id.btn_delete_selected);
        Button btnDeleteAll = dialogView.findViewById(R.id.btn_delete_all);
        Button btnShare = dialogView.findViewById(R.id.btn_share);
        Button btnCancel = dialogView.findViewById(R.id.btn_cancel);

        // 创建适配器
        ArrayAdapter<File> adapter = new ArrayAdapter<File>(this, R.layout.item_report, reports) {
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View view = convertView;
                if (view == null) {
                    view = getLayoutInflater().inflate(R.layout.item_report, parent, false);
                }

                File file = getItem(position);
                CheckBox checkBox = view.findViewById(R.id.checkbox);
                TextView fileName = view.findViewById(R.id.file_name);

                fileName.setText(file.getName());
                checkBox.setChecked(listView.isItemChecked(position));

                return view;
            }
        };

        listView.setAdapter(adapter);

        // 列表项点击事件 - 打开文件
        listView.setOnItemClickListener((parent, view, position, id) -> {
            openGeneratedFile(reports.get(position));
        });

        // 列表项长按事件 - 切换选中状态
        listView.setOnItemLongClickListener((parent, view, position, id) -> {
            boolean newState = !listView.isItemChecked(position);
            listView.setItemChecked(position, newState);
            adapter.notifyDataSetChanged();
            return true;
        });

        // 删除选中按钮
        btnDeleteSelected.setOnClickListener(v -> {
            SparseBooleanArray checked = listView.getCheckedItemPositions();
            List<File> filesToDelete = new ArrayList<>();

            for (int i = 0; i < checked.size(); i++) {
                if (checked.valueAt(i)) {
                    filesToDelete.add(reports.get(checked.keyAt(i)));
                }
            }

            if (!filesToDelete.isEmpty()) {
                new AlertDialog.Builder(this)
                        .setTitle("确认删除")
                        .setMessage("确定要删除选中的 " + filesToDelete.size() + " 个报告吗？")
                        .setPositiveButton("确定", (dialog1, which1) -> {
                            deleteSelectedReports(filesToDelete, start, end);
                            if (reportcurrentDialog != null && reportcurrentDialog.isShowing()) {
                                reportcurrentDialog.dismiss();
                            }
                        })
                        .setNegativeButton("取消", null)
                        .show();
            } else {
                Toast.makeText(this, "请先选择要删除的报告", Toast.LENGTH_SHORT).show();
            }
        });

        // 删除全部按钮
        btnDeleteAll.setOnClickListener(v -> {
            if (!reports.isEmpty()) {
                new AlertDialog.Builder(this)
                        .setTitle("确认删除")
                        .setMessage("确定要删除全部 " + reports.size() + " 个报告吗？")
                        .setPositiveButton("确定", (dialog1, which1) -> {
                            deleteAllReports(reports, start, end);
                            if (reportcurrentDialog != null && reportcurrentDialog.isShowing()) {
                                reportcurrentDialog.dismiss();
                            }
                        })
                        .setNegativeButton("取消", null)
                        .show();
            }
        });

        // 分享按钮
        btnShare.setOnClickListener(v -> {
            SparseBooleanArray checked = listView.getCheckedItemPositions();
            List<File> filesToShare = new ArrayList<>();

            for (int i = 0; i < checked.size(); i++) {
                if (checked.valueAt(i)) {
                    filesToShare.add(reports.get(checked.keyAt(i)));
                }
            }

            if (!filesToShare.isEmpty()) {
                shareSelectedFiles(filesToShare);
            } else {
                Toast.makeText(this, "请先选择要分享的报告", Toast.LENGTH_SHORT).show();
            }
        });

        // 返回按钮
        btnCancel.setOnClickListener(v -> {
            if (reportcurrentDialog != null && reportcurrentDialog.isShowing()) {
                reportcurrentDialog.dismiss();
            }
        });

        // 创建并显示对话框
        if (reportcurrentDialog != null && reportcurrentDialog.isShowing()) {
            reportcurrentDialog.dismiss();
        }
        reportcurrentDialog = builder.create();
        reportcurrentDialog.show();
    }

    // 删除选中报告的方法
    private void deleteSelectedReports(List<File> filesToDelete, String start, String end) {
        int successCount = 0;
        for (File file : filesToDelete) {
            if (file.delete()) {
                successCount++;
            }
        }

        Toast.makeText(this, "已删除 " + successCount + " 个报告", Toast.LENGTH_SHORT).show();

        // 删除后刷新列表
        showReportsList(start, end);
    }

    private void shareSelectedFiles(List<File> filesToShare) {
        if (filesToShare.size() == 1) {
            // 单个文件直接分享
            shareGeneratedFile(filesToShare.get(0));
        } else {
            // 多个文件需要先压缩或使用其他方式分享
            shareMultipleFiles(filesToShare);
        }
    }

    private void shareGeneratedFile(File file) {
        try {
            Uri fileUri = FileProvider.getUriForFile(this,
                    getApplicationContext().getPackageName() + ".provider",
                    file);

            Intent shareIntent = new Intent(Intent.ACTION_SEND);
            shareIntent.setType(getMimeType(file.getAbsolutePath()));
            shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
            shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

            // 验证是否有应用可以处理这个Intent
            if (shareIntent.resolveActivity(getPackageManager()) != null) {
                startActivity(Intent.createChooser(shareIntent, "分享报告"));
            } else {
                Toast.makeText(this, "没有找到可以处理此文件的应用程序", Toast.LENGTH_SHORT).show();
            }
        } catch (IllegalArgumentException e) {
            showErrorDialog("分享错误:", e.getMessage());
            e.printStackTrace();
        }
    }

    private void shareMultipleFiles(List<File> files) {
        try {
            ArrayList<Uri> uris = new ArrayList<>();
            String packageName = getApplicationContext().getPackageName();

            for (File file : files) {
                Uri fileUri = FileProvider.getUriForFile(this,
                        packageName + ".provider",
                        file);
                uris.add(fileUri);
            }

            Intent shareIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
            shareIntent.setType("*/*");
            shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
            shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

            // 验证是否有应用可以处理这个Intent
            if (shareIntent.resolveActivity(getPackageManager()) != null) {
                startActivity(Intent.createChooser(shareIntent, "分享多个报告"));
            } else {
                Toast.makeText(this, "没有找到可以处理这些文件的应用程序", Toast.LENGTH_SHORT).show();
            }
        } catch (IllegalArgumentException e) {
            Toast.makeText(this, "分享文件失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }

    // 删除全部报告的方法
    private void deleteAllReports(List<File> reports, String start, String end) {
        int successCount = 0;
        for (File file : reports) {
            if (file.delete()) {
                successCount++;
            }
        }

        Toast.makeText(this, "已删除 " + successCount + " 个报告", Toast.LENGTH_SHORT).show();

        // 删除后刷新列表
        showReportsList(start, end);
    }
    // 获取MIME类型

    private void initApp() {
        Button btnConvert = findViewById(R.id.btn_convert);
        Button btnread = findViewById(R.id.btn_readdocx);
        Button readoothermsg = findViewById(R.id.readothermsg);
        btnread.setOnClickListener(v -> {
            showReportsList("output", ".docx");
        });
        readoothermsg.setOnClickListener(v ->
        {
            showErrorDialog("othermsg:", dataManager.getOthermsg());
        });
        btnConvert.setOnClickListener(v -> {
            if (PermissionUtils.checkAndRequestPermissions(this)) {
                // 显示处理中状态
                updateStatus("正在处理...");

                showDateRangePicker();
            }

        });
    }

    private void showDateRangePicker() {
        // 创建日期选择对话框
        MaterialDatePicker<Pair<Long, Long>> picker = MaterialDatePicker.Builder
                .dateRangePicker()
                .setTitleText("选择日期范围")
                .setSelection(Pair.create(
                        MaterialDatePicker.thisMonthInUtcMilliseconds(),
                        MaterialDatePicker.todayInUtcMilliseconds()
                ))
                .build();

        picker.addOnPositiveButtonClickListener(selection -> {
            try {
                // 保存原始时间戳
                startTimestamp = selection.first;
                endTimestamp = selection.second;

                // 格式化为日期字符串
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
                startDateStr = sdf.format(new Date(startTimestamp));
                endDateStr = sdf.format(new Date(endTimestamp));

                // 查询数据库
                queryDatabasesAndGenerateReport();
            } catch (Exception e) {
                e.printStackTrace();
                Toast.makeText(this, "日期处理错误: " + e.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });

        picker.show(getSupportFragmentManager(), "DATE_RANGE_PICKER");
    }

    private void queryDatabasesAndGenerateReport() {
        updateStatus("正在查询数据库...");

        try {
            // 调整时间范围
            Calendar startCal = Calendar.getInstance();
            startCal.setTimeInMillis(startTimestamp);
            startCal.set(Calendar.HOUR_OF_DAY, 0);
            startCal.set(Calendar.MINUTE, 0);
            startCal.set(Calendar.SECOND, 0);
            startCal.set(Calendar.MILLISECOND, 0);

            Calendar endCal = Calendar.getInstance();
            endCal.setTimeInMillis(endTimestamp);
            endCal.set(Calendar.HOUR_OF_DAY, 23);
            endCal.set(Calendar.MINUTE, 59);
            endCal.set(Calendar.SECOND, 59);
            endCal.set(Calendar.MILLISECOND, 999);

            long adjustedStart = startCal.getTimeInMillis();
            long adjustedEnd = endCal.getTimeInMillis();

            // 异步查询
            new Thread(() -> {

                try {


                    List<ImageEntity> listFromDb = db.imageDao().getImagesByTimeRange(adjustedStart, adjustedEnd);
                    List<ImageEntity> listFromDb2 = db2.imageDao().getImagesByTimeRange(adjustedStart, adjustedEnd);

                    // 合并结果
                    List<ImageEntity> combinedList = new ArrayList<>();
                    combinedList.addAll(listFromDb);
                    combinedList.addAll(listFromDb2);

                    // 回到主线程处理结果
                    runOnUiThread(() -> {
                        if (combinedList.isEmpty()) {
                            updateStatus("所选时间段内没有数据");
                            Toast.makeText(this, "所选时间段内没有数据", Toast.LENGTH_SHORT).show();
                        } else {
                            updateStatus("正在生成报告...");
                            generateReportJson("testjson/input.json", combinedList,
                                    "output.json", startDateStr, endDateStr);
                        }
                    });
                } catch (Exception e) {
                    runOnUiThread(() -> {
                        updateStatus("查询失败: " + e.getMessage());
                        Toast.makeText(this, "查询失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
                    });
                } finally {
                    if (db != null) db.close();
                    if (db2 != null) db2.close();
                }
            }).start();
        } catch (Exception e) {
            updateStatus("处理日期错误: " + e.getMessage());
            Toast.makeText(this, "处理日期错误: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    private String readJsonFromOutputFile(File outputFile) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader(outputFile));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            reader.close();
            return sb.toString();
        } catch (IOException e) {
            showToast("读取输出JSON文件错误: " + e.getMessage());
            return null;
        }
    }

    private File convertJsonToDocx(Context context, File outfile, String outputFileName) {

        String jsonData = readJsonFromOutputFile(outfile);
        if (jsonData == null || jsonData.trim().isEmpty()) {
            showErrorDialog("JSON错误", "空JSON数据或读取失败");
            return null;
        }

        // 验证JSON格式


        File outputFile = new File(context.getExternalFilesDir(null), outputFileName);

        try {
            Python py = Python.getInstance();
            PyObject result = py.getModule("test")
                    .callAttrThrows("json_to_docx", jsonData, outputFile.getAbsolutePath());

            // 如果没有异常抛出，则认为成功
            showToast("DOCX生成成功: " + outputFile.getPath());
            return outputFile;

        } catch (PyException e) {
            // 专门处理Python异常
            String pythonError = getPythonErrorDetails(e);
            showErrorDialog("Python处理错误", pythonError);
            return null;
        } catch (Throwable e) {
            // 处理其他Java异常
            String errorMsg = buildErrorMessage((Exception) e);
            showErrorDialog("转换失败", errorMsg);
            Log.e(TAG, errorMsg);
            return null;
        }
    }

    // 构建完整的错误信息
    private String buildErrorMessage(Exception e) {
        return "错误类型: " + e.getClass().getSimpleName() + "\n\n" +
                "错误信息: " + e.getMessage() + "\n\n" +
                "堆栈跟踪:\n" + Log.getStackTraceString(e);
    }

    // 显示错误对话框（主线程安全）
    private void showErrorDialog(String title, String message) {
        runOnUiThread(() -> {
            new AlertDialog.Builder(this)
                    .setTitle(title)
                    .setMessage(message)
                    .setPositiveButton("确定", null)
                    .setNegativeButton("复制", (dialog, which) -> {
                        ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
                        ClipData clip = ClipData.newPlainText("复制信息", message);
                        clipboard.setPrimaryClip(clip);
                        // Optional: Show a toast to confirm the copy
                        Toast.makeText(this, "信息已复制", Toast.LENGTH_SHORT).show();
                    })
                    .show();
        });
    }


    // 获取Python错误详情（优化版）
    private String getPythonErrorDetails(PyException e) {
        try {
            Python py = Python.getInstance();
            PyObject traceback = py.getModule("traceback");
            PyObject formatExc = traceback.callAttr("format_exc");

            return "Python脚本错误:\n\n" +
                    formatExc.toString() +
                    "\n\n原始异常: " + e.getMessage();
        } catch (Exception tracebackError) {
            return "无法解析Python错误详情: " + e.getMessage() +
                    "\n(解析traceback时出错: " + tracebackError.getMessage() + ")";
        }
    }

    private String readJsonFromAssets(Context context, String filename) {
        try {
            InputStream is = context.getAssets().open(filename);
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            reader.close();
            return sb.toString();
        } catch (IOException e) {
            showToast("读取JSON文件错误: " + e.getMessage());
            return null;
        }
    }

    private void openGeneratedFile(File file) {
        if (file == null || !file.exists()) {
            showToast("文件不存在或创建失败");
            return;
        }

        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri fileUri = FileProvider.getUriForFile(
                this,
                getPackageName() + ".provider",  // 必须与 AndroidManifest.xml 中的 authorities 一致
                file);

        // 根据文件扩展名动态设置 MIME 类型
        String mimeType = getMimeType(file.getAbsolutePath());
        intent.setDataAndType(fileUri, mimeType);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

        try {
            startActivity(intent);
        } catch (ActivityNotFoundException e) {
            showToast("没有找到可以打开该文件的应用");
            // 提示用户安装支持的应用（如 WPS、Office）
            showOfficeInstallDialog();
        }
    }

    private void showOfficeInstallDialog() {
        mainHandler.post(() -> {
            new AlertDialog.Builder(this)
                    .setTitle("无法打开文件")
                    .setMessage("您的设备上没有安装可以打开Word文档的应用。是否要安装Microsoft Word?")
                    .setPositiveButton("安装", (d, w) -> {
                        try {
                            startActivity(new Intent(Intent.ACTION_VIEW,
                                    Uri.parse("market://details?id=com.microsoft.office.word")));
                        } catch (ActivityNotFoundException ex) {
                            startActivity(new Intent(Intent.ACTION_VIEW,
                                    Uri.parse("https://play.google.com/store/apps/details?id=com.microsoft.office.word")));
                        }
                    })
                    .setNegativeButton("取消", null)
                    .show();
        });
    }

    // 辅助方法：在主线程更新状态
    private void updateStatus(String message) {
        tvStatus.setText(message);
    }

    // 辅助方法：在主线程显示Toast
    private void showToast(String message) {
        mainHandler.post(() -> Toast.makeText(this, message, Toast.LENGTH_SHORT).show());
    }

    private String getMimeType(String url) {
        // 初始化类型为null
        String type = null;

        // 从URL/文件路径中获取文件扩展名
        String extension = MimeTypeMap.getFileExtensionFromUrl(url);

        // 如果扩展名不为空
        if (extension != null) {
            // 根据扩展名获取对应的MIME类型
            type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
        }

        // 如果找到了MIME类型则返回，否则返回通用类型"*/*"
        return type != null ? type : "*/*";
    }


    private void initializeViews() {
        selectTimeButton = findViewById(R.id.selectTimeButton);
        startTimeText = findViewById(R.id.startTimeText);
        endTimeText = findViewById(R.id.endTimeText);
        btnUploadVideos2 = findViewById(R.id.btn_upload_videos2);
        btnUploadVideos = findViewById(R.id.btn_upload_videos);
        etUploadInterval = findViewById(R.id.et_upload_interval);
        etUploadInterval.setOnFocusChangeListener((v, hasFocus) -> {
            if (hasFocus) {
                showKeyboard(v);
            } else {
                hideKeyboard();
            }
        });
        btnFailedAudios = findViewById(R.id.btn_failed_audios);
        btnFailedAudios2 = findViewById(R.id.btn_success_audios);

        btnSetInterval = findViewById(R.id.btn_set_interval);
        btnStartTimedUpload = findViewById(R.id.btn_start_timed_upload);
        btnStopTimedUpload = findViewById(R.id.btn_stop_timed_upload);
        btnUploadQueue = findViewById(R.id.btn_upload_queue);
        btnStopUpload = findViewById(R.id.btn_stop_upload);
        btnHistory = findViewById(R.id.btn_history);
        btnHistory2 = findViewById(R.id.btn_history2);
        statusText = findViewById(R.id.status_text);
        switchMonitor = findViewById(R.id.switch_monitor);
        locationText = findViewById(R.id.location_text);
        btnAdmin = findViewById(R.id.btnAdmin);
        tvUser = findViewById(R.id.tv_user);

        btnClearProject = findViewById(R.id.btnClearProject);
        actvProject = findViewById(R.id.etProject);
        btnClearTurbine = findViewById(R.id.btnClearTurbine);
        actvTurbine = findViewById(R.id.etTurbine);
        btnClearPart = findViewById(R.id.btnClearPart);
        actvPart = findViewById(R.id.etPart);

        btnGenerateReport = findViewById(R.id.btn_generate_report);
        btnReadReport = findViewById(R.id.btn_read_report);
        tvStatus = findViewById(R.id.tv_status);
        etWeather = findViewById(R.id.et_weather);
        etTemperature = findViewById(R.id.et_temperature);
        etHumidity = findViewById(R.id.et_humidity);
        btnSaveWeather = findViewById(R.id.btn_save_weather);

        // 初始化天气信息显示视图
        tvWeatherDisplay = findViewById(R.id.tv_weather_display);
        tvTemperatureDisplay = findViewById(R.id.tv_temperature_display);
        changepassword = findViewById(R.id.changePassword);

        spinnerImageSource = findViewById(R.id.spinner_image_source);
        tvHumidityDisplay = findViewById(R.id.tv_humidity_display);
    }

    private void initializeDatabase() {
        db = Room.databaseBuilder(getApplicationContext(),
                AppDatabase.class, "image-database").build();
        db2 = Room.databaseBuilder(getApplicationContext(),
                AppDatabase.class, "image-database2").build();
    }

    @SuppressLint("UnspecifiedRegisterReceiverFlag")
    private void initializeReceivers() {
        updateReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                password = intent.getStringExtra("password");
                dataManager.setPartId(partId);
                dataManager.setTurbineId(turbineId);
                dataManager.setPartName(partName);
            }
        };

        IntentFilter filter = new IntentFilter(ACTION_UPDATE_VALUES);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            registerReceiver(updateReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
        } else {
            registerReceiver(updateReceiver, filter);
        }
    }

    private void showKeyboard(View view) {
        if (view.requestFocus()) {
            view.postDelayed(() -> {
                if (inputMethodManager == null) {
                    inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                }
                if (inputMethodManager != null) {
                    inputMethodManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
                }
            }, 100);
        }
    }

    private void hideKeyboard() {
        View view = this.getCurrentFocus();
        if (view != null) {
            if (inputMethodManager == null) {
                inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            }
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
            // 清除当前焦点
            view.clearFocus();
        }
    }

    private void initializePermissionLaunchers() {
        // Video picker launcher
        videoPickerLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                    if (result.getResultCode() == RESULT_OK && result.getData() != null) {
                        handleVideoSelection(result.getData());
                    }
                });

        // Permission request launcher
        requestPermissionLauncher = registerForActivityResult(
                new ActivityResultContracts.RequestMultiplePermissions(),
                permissions -> {
                    if (permissions.values().stream().allMatch(Boolean::booleanValue)) {
                        openVideoPicker();
                    } else {
                        Toast.makeText(this, "需要权限才能选择视频", Toast.LENGTH_SHORT).show();
                    }
                });

        // Overlay permission launcher
        overlayPermissionLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                    new Handler(Looper.getMainLooper()).postDelayed(() -> {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                            if (Settings.canDrawOverlays(MainActivity.this)) {
                                startFloatingService();
                            } else {
                                Toast.makeText(MainActivity.this,
                                        "需要悬浮窗权限才能显示悬浮窗", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }, 500);
                });
    }

    private void initialUser() {
        Intent intent = getIntent();
        currentUsername = intent.getStringExtra("username");
        tvUser.setText(currentUsername);
        inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    }

    private void requestInitialPermissions() {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            String[] permissions = {
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.RECORD_AUDIO,
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.POST_NOTIFICATIONS
            };

            if (checkSelfPermission(permissions)) {

                initLocationManager();
            } else {

                ActivityCompat.requestPermissions(this, permissions, PERMISSIONS_REQUEST_CODE);
            }
        } else {

            String[] permissions = {
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.RECORD_AUDIO,
                    Manifest.permission.ACCESS_FINE_LOCATION
            };

            if (checkSelfPermission(permissions)) {
                initLocationManager();
            } else {
                ActivityCompat.requestPermissions(this, permissions, PERMISSIONS_REQUEST_CODE);
            }
        }

        // Special handling for overlay permission
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
            requestOverlayPermission();
        }
    }

    private boolean checkSelfPermission(String[] permissions) {
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(this, permission)
                    != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    private void setupButtonListeners() {
        // Set up all button click listeners here
        btnUploadVideos2.setOnClickListener(v -> openVideoPicker());
        btnUploadVideos.setOnClickListener(v -> showVideoDateTimePicker());
        selectTimeButton.setOnClickListener(v -> showDateTimePicker());

        btnSetInterval.setOnClickListener(v -> {
            hideKeyboard(); // 先隐藏键盘
            setUploadInterval(); // 然后执行设置逻辑
        });
        btnStartTimedUpload.setOnClickListener(v -> startTimedUpload());
        btnStopTimedUpload.setOnClickListener(v -> stopTimedUpload());

        btnUploadQueue.setOnClickListener(v -> startUploadQueue());
        btnStopUpload.setOnClickListener(v -> stopUploadQueue());
        btnFailedAudios.setOnClickListener(v -> showFailedAudios());
        btnFailedAudios2.setOnClickListener(v -> showSuccessAudios());
        btnHistory.setOnClickListener(v -> showHistory(db, "历史记录（点击查看大图）", "删除所有记录", "确定要删除所有历史记录吗？"));
        btnHistory2.setOnClickListener(v -> showHistory(db2, "缓存队列（点击查看大图）", "删除所有缓存", "确定要删除所有缓存吗？"));
        switchMonitor.setChecked(false);
        switchMonitor.setOnCheckedChangeListener((buttonView, isChecked) -> {
            if (isChecked) {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                        != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(
                            this,
                            new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                            LOCATION_PERMISSION_REQUEST_CODE);
                } else {
                    checkRecordPermission();
                }
            } else {
                stopMonitoring();
            }
        });

        btnAdmin.setOnClickListener(v -> {
            startActivity(new Intent(MainActivity.this, AdminActivity.class));
        });
    }

    private void showFailedAudios() {
        new Thread(() -> {
            List<AudioEntity> failedAudios = db.AudioDao().getAllAudios(); // Assuming you have getAll() in AudioDao

            runOnUiThread(() -> {
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle("上传失败的录音");

                if (failedAudios == null || failedAudios.isEmpty()) {
                    builder.setMessage("没有上传失败的录音");
                    builder.setPositiveButton("确定", null);
                    builder.show();
                    return;
                }

                List<String> displayItems = new ArrayList<>();
                for (AudioEntity audio : failedAudios) {
                    displayItems.add(String.format("录音路径: %s\n图片路径: %s\n时间: %s",
                            audio.getAudioPath(),
                            audio.getImagePath(),
                            audio.getTime()));
                }

                // Convert to array for the adapter
                String[] items = displayItems.toArray(new String[0]);

                builder.setAdapter(new ArrayAdapter<>(this,
                                android.R.layout.simple_list_item_1, items),
                        (dialog, which) -> {

                        });

                // Add delete and retry buttons
                builder.setNegativeButton("一键删除", (dialog, which) -> deleteAllFailedAudios(failedAudios));
                builder.setNeutralButton("一键上传", (dialog, which) -> retryAllFailedAudios(failedAudios));

                builder.show();
            });
        }).start();
    }

    private void showSuccessAudios() {
        new Thread(() -> {
            List<AudioEntity> successAudios = db2.AudioDao().getAllAudios();

            runOnUiThread(() -> {
                // 使用自定义主题的 AlertDialog
                AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.CustomAlertDialog);
                builder.setTitle("上传成功的录音");

                // 设置自定义标题样式
                TextView titleView = new TextView(this);
                titleView.setText("上传成功的录音");
                titleView.setTextSize(20);
                titleView.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
                titleView.setPadding(40, 40, 40, 20);
                titleView.setGravity(Gravity.CENTER);
                builder.setCustomTitle(titleView);

                if (successAudios == null || successAudios.isEmpty()) {
                    builder.setMessage("没有上传成功的录音");
                    builder.setPositiveButton("确定", null);
                    builder.show();
                    return;
                }

                // 创建自定义适配器
                ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                        R.layout.audio_item_layout, R.id.audio_item_text) {
                    @Override
                    public View getView(int position, View convertView, ViewGroup parent) {
                        View view = super.getView(position, convertView, parent);
                        TextView textView = view.findViewById(R.id.audio_item_text);

                        // 设置item样式
                        textView.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.textColor));
                        textView.setTextSize(16);
                        textView.setPadding(30, 30, 30, 30);

                        return view;
                    }
                };

                // 添加数据到适配器
                for (AudioEntity audio : successAudios) {
                    adapter.add(String.format("录音名称: %s\n时间: %s",
                            getFileNameFromPath(audio.getAudioPath()),
                            audio.getTime()));
                }

                builder.setAdapter(adapter, (dialog, which) -> {
                    // 点击item打开录音文件
                    AudioEntity selectedAudio = successAudios.get(which);
                    openAudioFile(selectedAudio.getAudioPath());
                });

                // 添加删除按钮
                builder.setNegativeButton("一键删除", (dialog, which) -> deleteAllSuccessAudios(successAudios));

                // 添加关闭按钮
                builder.setPositiveButton("关闭", null);

                AlertDialog dialog = builder.create();

                // 设置Dialog窗口属性
                Window window = dialog.getWindow();
                if (window != null) {
                    window.setBackgroundDrawable(new ColorDrawable(Color.WHITE));
                    window.setGravity(Gravity.CENTER);
                }

                dialog.show();

                // 设置按钮样式
                Button negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
                negativeButton.setTextColor(ContextCompat.getColor(this, R.color.colorAccent));

                Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
                positiveButton.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
            });
        }).start();
    }

    // 从路径中获取文件名
    private String getFileNameFromPath(String path) {
        if (path == null || path.isEmpty()) return "未知录音";
        int index = path.lastIndexOf('/');
        return index != -1 ? path.substring(index + 1) : path;
    }

    // 打开录音文件
    private void openAudioFile(String audioPath) {
        File file = new File(audioPath);
        if (!file.exists()) {
            Toast.makeText(this, "录音文件不存在", Toast.LENGTH_SHORT).show();
            return;
        }

        try {
            // 使用正确的 authority
            Uri audioUri = FileProvider.getUriForFile(
                    this,
                    getPackageName() + ".provider",
                    file
            );
            Log.d("FileProvider", "转换后的URI: " + audioUri.toString());

            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(audioUri, "audio/*");
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

            // 检查是否有应用可以处理这个Intent
            if (intent.resolveActivity(getPackageManager()) != null) {
                startActivity(intent);
            } else {
                Toast.makeText(this, "没有找到可以播放录音的应用", Toast.LENGTH_SHORT).show();
            }
        } catch (IllegalArgumentException e) {
            Log.e("录音文件失败:", e.getMessage() + "路径为" + audioPath);
            showErrorDialog("打开录音文件错误:", e.getMessage() + "路径为" + audioPath);
        }
    }

    private void setupTimedUpload() {
        timedUploadHandler = new Handler(Looper.getMainLooper());
        SharedPreferences prefs = getSharedPreferences("UploadPrefs", MODE_PRIVATE);
        uploadIntervalMinutes = prefs.getInt("upload_interval", 0);
        if (uploadIntervalMinutes > 0) {
            etUploadInterval.setText(String.valueOf(uploadIntervalMinutes));
        }
    }

    private void deleteAllSuccessAudios(List<AudioEntity> audios) {
        new Thread(() -> {
            for (AudioEntity audio : audios) {

                db2.AudioDao().delete(audio);
            }

            runOnUiThread(() -> {
                Toast.makeText(this, "已删除所有成功录音", Toast.LENGTH_SHORT).show();
            });
        }).start();
    }

    private void deleteAllFailedAudios(List<AudioEntity> audios) {
        new Thread(() -> {
            for (AudioEntity audio : audios) {

                db.AudioDao().delete(audio);
            }

            runOnUiThread(() -> {
                Toast.makeText(this, "已删除所有失败录音", Toast.LENGTH_SHORT).show();
            });
        }).start();
    }

    private void retryAllFailedAudios(List<AudioEntity> audios) {
        new Thread(() -> {
            for (AudioEntity audio : audios) {
                executor.execute(() -> {
                    uploadAudio(audio.ImagePath, audio.AudioPath, audio.time);
                    db.AudioDao().deleteByPath(audio.AudioPath);
                });
            }

            BackgroundToast.show(MainActivity.this, "录音手动上传成功");
        }).start();
    }


    private boolean checkOverlayPermission2() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                requestOverlayPermission2();
                return false;
            }
        }
        return true;
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void requestOverlayPermission2() {
        try {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
            intent.setData(Uri.parse("package:" + getPackageName()));
            overlayPermissionLauncher.launch(intent);
        } catch (Exception e) {
            // 兼容厂商 ROM
            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            intent.setData(Uri.parse("package:" + getPackageName()));
            startActivity(intent);
        }
    }


    private void startFloatingService() {
        Intent serviceIntent = new Intent(this, FloatingWindowService.class);
        serviceIntent.putExtra("PROJECT_ID", projectId);  // 添加projectID到Intent

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(serviceIntent);
        } else {
            startService(serviceIntent);
        }

    }

    private void openVideoPicker() {
        String[] requiredPermissions;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { // Android 14+
            requiredPermissions = new String[]{
                    Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_IMAGES
            };
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            requiredPermissions = new String[]{Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_IMAGES};
        } else {
            requiredPermissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE};
        }

        if (checkPermissions(requiredPermissions)) {
            launchVideoPicker();
        } else {
            requestPermissionLauncher.launch(requiredPermissions);
        }
    }

    private boolean checkPermissions(String[] permissions) {
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(this, permission)
                    != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    private void launchVideoPicker() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("video/*");
        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        videoPickerLauncher.launch(Intent.createChooser(intent, "选择视频"));
    }

    private void handleVideoSelection(Intent data) {
        List<Uri> videoUris = new ArrayList<>();

        if (data.getClipData() != null) {
            // 多选
            ClipData clipData = data.getClipData();
            for (int i = 0; i < clipData.getItemCount(); i++) {
                videoUris.add(clipData.getItemAt(i).getUri());
            }
        } else if (data.getData() != null) {
            // 单选
            videoUris.add(data.getData());
        }

        // 显示确认对话框
        showQualificationDialog(videoUris);
    }

    private void showQualificationDialog(List<Uri> videoUris) {
        new AlertDialog.Builder(this)
                .setTitle("机组合格确认")
                .setMessage("这批上传的机组视频是否合格？")
                .setPositiveButton("合格", (dialog, which) -> {
                    processVideosWithQualification(videoUris, 1);
                })
                .setNegativeButton("不合格", (dialog, which) -> {
                    processVideosWithQualification(videoUris, 0);
                })
                .setCancelable(false)
                .show();
    }

    private void processVideosWithQualification(List<Uri> videoUris, int qualified) {
        for (Uri videoUri : videoUris) {
            processVideoUri(videoUri, qualified);
        }
    }

    private void processVideoUri(Uri videoUri, int qualified) {
        String[] projection = {
                MediaStore.Video.Media.DATA,
                MediaStore.Video.Media.DATE_TAKEN,
                MediaStore.Video.Media.DURATION
        };

        try (Cursor cursor = getContentResolver().query(videoUri, projection, null, null, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
                long time = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATE_TAKEN));
                long duration = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION));

                String user = getCurrentUser();
                uploadVideo(path, time, duration, lastKnownLocation, user, qualified);
            }
        }
    }


    private void showVideoEndDateTimePicker() {
        final Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(startTime);
        calendar.add(Calendar.HOUR, 1);

        DatePickerDialog datePickerDialog = new DatePickerDialog(this,
                (view, year, month, day) -> {
                    calendar.set(year, month, day);
                    TimePickerDialog timePickerDialog = new TimePickerDialog(MainActivity.this,
                            (view1, hour, minute) -> {
                                calendar.set(Calendar.HOUR_OF_DAY, hour);
                                calendar.set(Calendar.MINUTE, minute);
                                endTime = calendar.getTimeInMillis();

                                if (endTime <= startTime) {
                                    Toast.makeText(MainActivity.this, "结束时间必须晚于开始时间", Toast.LENGTH_SHORT).show();
                                    showVideoEndDateTimePicker();
                                    return;
                                }

                                updateTimeDisplay();
                                showVideoConfirmationDialog();
                            }, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true);
                    timePickerDialog.setTitle("选择视频结束时间");
                    timePickerDialog.show();
                }, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
        datePickerDialog.setTitle("选择视频结束日期");
        datePickerDialog.show();
    }

    private void showVideoDateTimePicker() {
        final Calendar calendar = Calendar.getInstance();
        Toast.makeText(this, "请选择视频开始时间", Toast.LENGTH_SHORT).show();

        DatePickerDialog datePickerDialog = new DatePickerDialog(this,
                (view, year, month, day) -> {
                    calendar.set(year, month, day);
                    TimePickerDialog timePickerDialog = new TimePickerDialog(MainActivity.this,
                            (view1, hour, minute) -> {
                                calendar.set(Calendar.HOUR_OF_DAY, hour);
                                calendar.set(Calendar.MINUTE, minute);
                                startTime = calendar.getTimeInMillis();
                                updateTimeDisplay();
                                Toast.makeText(MainActivity.this, "请选择视频结束时间", Toast.LENGTH_SHORT).show();
                                showVideoEndDateTimePicker();
                            }, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true);
                    timePickerDialog.setTitle("选择视频开始时间");
                    timePickerDialog.show();
                }, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
        datePickerDialog.setTitle("选择视频开始日期");
        datePickerDialog.show();
    }

    private void showVideoConfirmationDialog() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
        String message = "确认上传以下时间范围内的视频吗？\n\n" +
                "开始时间: " + sdf.format(new Date(startTime)) + "\n" +
                "结束时间: " + sdf.format(new Date(endTime));

        new AlertDialog.Builder(this)
                .setTitle("确认视频查询")
                .setMessage(message)
                .setPositiveButton("确认", (dialog, which) -> checkVideoPermissionAndQuery())
                .setNegativeButton("取消", (dialog, which) -> Toast.makeText(MainActivity.this, "已取消视频查询", Toast.LENGTH_SHORT).show())
                .setNeutralButton("重新选择", (dialog, which) -> showVideoDateTimePicker())
                .show();
    }

    private void checkVideoPermissionAndQuery() {
        String[] permissions;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { // Android 14+
            permissions = new String[]{
                    Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_IMAGES
            };
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // Android 13
            permissions = new String[]{Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_IMAGES};
        } else { // Android 12-
            permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE};
        }

        if (checkAnyPermissionGranted(permissions)) {
            queryVideos();
        } else {
            ActivityCompat.requestPermissions(this, permissions, REQUEST_VIDEO_PERMISSION);

        }
    }


    private void queryVideos() {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(() -> {
            List<VideoInfo> videoList = new ArrayList<>();
            ContentResolver contentResolver = getContentResolver();
            Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;

            String[] projection = {
                    MediaStore.Video.Media._ID,
                    MediaStore.Video.Media.DATA,
                    MediaStore.Video.Media.DATE_TAKEN,
                    MediaStore.Video.Media.DURATION
            };

            String selection = MediaStore.Video.Media.DATE_TAKEN + " >= ? AND " +
                    MediaStore.Video.Media.DATE_TAKEN + " <= ?";
            String[] selectionArgs = {String.valueOf(startTime), String.valueOf(endTime)};

            String sortOrder = MediaStore.Video.Media.DATE_TAKEN + " DESC";

            try (Cursor cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)) {
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        String path = cursor.getString(1);
                        long time = cursor.getLong(2);
                        long duration = cursor.getLong(3);

                        videoList.add(new VideoInfo(path, time, duration));
                    }
                }
            } catch (Exception e) {
                Log.e("VideoQuery", "Error querying videos", e);
            } finally {
                executorService.shutdown();
            }

            final int count = videoList.size();
            runOnUiThread(() -> {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
                String message = "找到 " + count + " 个视频 (" +
                        sdf.format(new Date(startTime)) + " 到 " +
                        sdf.format(new Date(endTime)) + ")";

                if (count > 0) {
                    // 显示确认对话框
                    new AlertDialog.Builder(MainActivity.this)
                            .setTitle("视频上传确认")
                            .setMessage(message + "\n\n这些视频是否合格？")
                            .setPositiveButton("合格", (dialog, which) -> {
                                uploadVideosWithQualification(videoList, 1);
                            })
                            .setNegativeButton("不合格", (dialog, which) -> {
                                uploadVideosWithQualification(videoList, 0);
                            })
                            .show();
                } else {
                    Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
                }
            });
        });
    }

    // 辅助类，用于存储视频信息
    private static class VideoInfo {
        String path;
        long time;
        long duration;

        VideoInfo(String path, long time, long duration) {
            this.path = path;
            this.time = time;
            this.duration = duration;
        }
    }

    // 批量上传视频并设置合格标记
    private void uploadVideosWithQualification(List<VideoInfo> videoList, int qualified) {
        String user = getCurrentUser();
        for (VideoInfo video : videoList) {
            uploadVideo(video.path, video.time, video.duration, lastKnownLocation, user, qualified);
        }
    }

    // 添加视频上传方法
    private void uploadVideo(String filePath, long time, long duration, Location location, String user, int q) {
        File file = new File(filePath);
        double latitude = location != null ? location.getLatitude() : 0;
        double longitude = location != null ? location.getLongitude() : 0;
        double altitude = location != null ? location.getAltitude() : 0;
        String finalunit = partId == null ? "0" : partId;
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("file", file.getName(),
                        RequestBody.create(file, MediaType.parse("video/*")))
                .addFormDataPart("shootingTime", String.valueOf(time))
                .addFormDataPart("duration", String.valueOf(duration))
                .addFormDataPart("latitude", String.valueOf(latitude))
                .addFormDataPart("longitude", String.valueOf(longitude))
                .addFormDataPart("altitude", String.valueOf(altitude))
                .addFormDataPart("workerUserId", user)
                .addFormDataPart("partId", finalunit)
                .addFormDataPart("qualified", String.valueOf(q))
                .build();

        Request request = new Request.Builder()
                .url(RetrofitClient.BASE_URL + "/video-file-info/batch-upload")
                .addHeader("Authorization", authToken)// 修改为您的视频上传URL
                .post(requestBody)
                .build();

        httpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                BackgroundToast.show(
                        MainActivity.this,
                        "视频上传失败: " + e.getMessage()
                );
            }

            @Override
            public void onResponse(Call call, Response response) {
                runOnUiThread(() -> {
                    if (response.isSuccessful()) {
                        BackgroundToast.show(
                                MainActivity.this,
                                "视频上传成功: " + response.code()
                        );
                    } else {
                        BackgroundToast.show(
                                MainActivity.this,
                                "视频上传失败: " + response.code()
                        );
                    }
                });
            }
        });
    }

    private void initFloatingActionButton() {
        if (!checkOverlayPermission()) {
            requestOverlayPermission();
            return;
        }

        floatingActionButton = new FloatingActionButton(this);
        floatingActionButton.setSize(FloatingActionButton.SIZE_MINI);
        floatingActionButton.setImageResource(R.drawable.ic_mic_off);
        floatingActionButton.setBackgroundTintList(ColorStateList.valueOf(Color.RED));

        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
                        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
                        WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
                        WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
                        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);

        params.gravity = Gravity.TOP | Gravity.START;
        params.x = 0;
        params.y = 100;

        try {
            WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
            windowManager.addView(floatingActionButton, params);
        } catch (Exception e) {
            Toast.makeText(this, "需要悬浮窗权限才能显示悬浮球", Toast.LENGTH_SHORT).show();
            return;
        }

        floatingActionButton.setOnTouchListener(new View.OnTouchListener() {
            private int initialX;
            private int initialY;
            private float initialTouchX;
            private float initialTouchY;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
                WindowManager.LayoutParams params = (WindowManager.LayoutParams) floatingActionButton.getLayoutParams();

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        initialX = params.x;
                        initialY = params.y;
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();
                        return true;

                    case MotionEvent.ACTION_MOVE:
                        params.x = initialX + (int) (event.getRawX() - initialTouchX);
                        params.y = initialY + (int) (event.getRawY() - initialTouchY);
                        windowManager.updateViewLayout(floatingActionButton, params);
                        return true;

                    case MotionEvent.ACTION_UP:
                        if (Math.abs(event.getRawX() - initialTouchX) < 10 &&
                                Math.abs(event.getRawY() - initialTouchY) < 10) {
                            floatingActionButton.performClick();
                        }
                        return true;
                }
                return false;
            }
        });

        floatingActionButton.setOnClickListener(v -> {
            if (isRecording) {
                stopVoiceRecording();
            } else {
                if (checkRecordPermission1()) {
                    startVoiceRecording();
                } else {
                    requestRecordPermission();
                }
            }
        });
    }

    private boolean checkAndRequestNotificationPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
                    != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(
                        this,
                        new String[]{Manifest.permission.POST_NOTIFICATIONS},
                        NOTIFICATION_PERMISSION_REQUEST_CODE
                );
                return false;
            }
        }
        return true;
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    "recording_channel",
                    "Recording Service",
                    NotificationManager.IMPORTANCE_LOW
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }

    private boolean checkOverlayPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return Settings.canDrawOverlays(this);
        }
        return true;
    }

    private void requestOverlayPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE) {
            if (checkOverlayPermission()) {

            } else {
                Toast.makeText(this, "悬浮窗权限被拒绝，无法显示悬浮球", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private boolean checkRecordPermission1() {
        return ContextCompat.checkSelfPermission(this,
                Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
    }

    private void requestRecordPermission() {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.RECORD_AUDIO},
                AUDIO_PERMISSION_REQUEST_CODE);
    }

    private void startVoiceRecording() {
        Intent serviceIntent = new Intent(this, RecordingService.class);
        serviceIntent.setAction("start_recording");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(serviceIntent);
        } else {
            startService(serviceIntent);
        }

        isRecording = true;
        dataManager.setIsRecording(isRecording);
        floatingActionButton.setImageResource(R.drawable.ic_mic_on);

    }

    private void stopVoiceRecording() {
        Intent serviceIntent = new Intent(this, RecordingService.class);
        serviceIntent.setAction("stop_recording");
        startService(serviceIntent);

        isRecording = false;
        dataManager.setIsRecording(isRecording);
        floatingActionButton.setImageResource(R.drawable.ic_mic_off);
    }

    private String getPartName(int b) {
        return "叶片" + b;
    }

    private void queryPhotos() {
        // 定义查询时间范围的条件（示例，可根据需要修改）
        String selection = MediaStore.Images.Media.DATE_TAKEN + " BETWEEN ? AND ? AND" +
                "(" + MediaStore.Images.Media.DATA + " LIKE '%/DCIM/%' OR " +
                MediaStore.Images.Media.DATA + " LIKE '%/Camera/%')";
        ;

        // 使用Executor替代AsyncTask
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(() -> {
            int count = 0;
            ContentResolver contentResolver = getContentResolver();
            Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

            String[] projection = {
                    MediaStore.Images.Media._ID,
                    MediaStore.Images.Media.DATA,
                    MediaStore.Images.Media.DATE_TAKEN,
                    MediaStore.Images.Media.LATITUDE,
                    MediaStore.Images.Media.LONGITUDE
            };

            String[] selectionArgs = {String.valueOf(startTime), String.valueOf(endTime)};
            String sortOrder = MediaStore.Images.Media.DATE_TAKEN + " DESC";

            try (Cursor cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)) {
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
                        String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
                        long time = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_TAKEN));

                        // 初始化位置信息
                        double latitude = 0.0;
                        double longitude = 0.0;
                        double altitude = 0.0;

                        // 从媒体库读取位置信息（如果有）
                        int latIndex = cursor.getColumnIndex(MediaStore.Images.Media.LATITUDE);
                        int lngIndex = cursor.getColumnIndex(MediaStore.Images.Media.LONGITUDE);
                        if (latIndex != -1 && lngIndex != -1) {
                            latitude = cursor.getDouble(latIndex);
                            longitude = cursor.getDouble(lngIndex);
                        }

                        // 改进位置获取
                        try {
                            if (locationManager != null && checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                                Location lastLocation = locationManager.getLastKnownLocation(
                                        LocationManager.GPS_PROVIDER);
                                if (lastLocation != null) {
                                    lastKnownLocation = lastLocation;
                                    runOnUiThread(() -> updateLocationText(lastLocation));
                                }
                            }
                        } catch (SecurityException e) {
                            e.printStackTrace();
                        }

                        if (lastKnownLocation != null) {
                            latitude = lastKnownLocation.getLatitude();
                            longitude = lastKnownLocation.getLongitude();
                            altitude = lastKnownLocation.getAltitude();
                        }

                        // 改进EXIF高度读取
                        try {
                            ExifInterface exif = new ExifInterface(path);
                            String altitudeStr = exif.getAttribute(ExifInterface.TAG_GPS_ALTITUDE);
                            if (altitudeStr != null) {
                                String[] parts = altitudeStr.split("/");
                                if (parts.length == 2) {
                                    double alt = Double.parseDouble(parts[0]) /
                                            Double.parseDouble(parts[1]);
                                    altitude = alt;
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                        String user = getCurrentUser();
                        Log.d("PhotoQuery", "Processing photo for user: " + user);

                        // 使用更高效的方式生成缩略图
                        Bitmap thumbnail = null;
                        try {
                            BitmapFactory.Options options = new BitmapFactory.Options();
                            options.inJustDecodeBounds = true;
                            BitmapFactory.decodeFile(path, options);

                            options.inSampleSize = calculateInSampleSize(options, THUMBNAIL_SIZE, THUMBNAIL_SIZE);
                            options.inJustDecodeBounds = false;
                            thumbnail = BitmapFactory.decodeFile(path, options);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                        count++;
                        if (thumbnail != null) {
                            lastPhotoId = Math.max(lastPhotoId, id);


                            double finalAltitude = altitude;
                            double finalLongitude = longitude;
                            double finalLatitude = latitude;
                            String finalproject = projectId.isEmpty() ? "项目ID未填写" : projectId;

                            // 使用另一个线程执行上传或保存操作
                            Executors.newSingleThreadExecutor().execute(() -> {
                                if (isNetworkAvailable()) {
                                    uploadPhotoSync(path, time, lastKnownLocation, user, "0", finalproject, partId, turbineId, ChooseImageSource);

                                } else {
                                    db2.imageDao().insert(new ImageEntity(path, time,
                                            finalLatitude, finalLongitude,
                                            finalAltitude, user, "0", finalproject, partId, partName, turbineId, turbineName, false, Temperator, Humidity, Weather, ChooseImageSource));
                                }
                            });
                        }
                    }
                    cursor.close();
                }
            } catch (Exception e) {
                Log.e("PhotoQuery", "Error querying photos", e);
            } finally {
                executorService.shutdown();
            }

            // 更新UI需要在主线程执行
            final int finalCount = count;
            runOnUiThread(() -> {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
                Toast.makeText(MainActivity.this,
                        "找到 " + finalCount + " 张照片 (" +
                                sdf.format(new Date(startTime)) + " 到 " +
                                sdf.format(new Date(endTime)) + ")上传中",
                        Toast.LENGTH_LONG).show();
            });
        });
    }

    // 辅助方法计算采样大小
    private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

    private void showDateTimePicker() {
        hideKeyboard();
        final Calendar calendar = Calendar.getInstance();

        // Show prompt for start time selection
        Toast.makeText(this, "请选择开始时间", Toast.LENGTH_SHORT).show();

        // 日期选择器
        DatePickerDialog datePickerDialog = new DatePickerDialog(this,
                new DatePickerDialog.OnDateSetListener() {
                    @Override
                    public void onDateSet(DatePicker view, int year, int month, int day) {
                        calendar.set(year, month, day);

                        // 时间选择器
                        TimePickerDialog timePickerDialog = new TimePickerDialog(MainActivity.this,
                                new TimePickerDialog.OnTimeSetListener() {
                                    @Override
                                    public void onTimeSet(TimePicker view, int hour, int minute) {
                                        calendar.set(Calendar.HOUR_OF_DAY, hour);
                                        calendar.set(Calendar.MINUTE, minute);
                                        startTime = calendar.getTimeInMillis();

                                        // Update start time display immediately
                                        updateTimeDisplay();

                                        // Show prompt for end time selection
                                        Toast.makeText(MainActivity.this, "请选择结束时间", Toast.LENGTH_SHORT).show();

                                        // 选择结束时间
                                        showEndDateTimePicker();
                                    }
                                }, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true);
                        timePickerDialog.setTitle("选择开始时间");
                        timePickerDialog.show();
                    }
                }, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
        datePickerDialog.setOnShowListener(dialog -> {
            // 确保日期选择器获得焦点
            datePickerDialog.getButton(DialogInterface.BUTTON_POSITIVE).requestFocus();
        });
        datePickerDialog.setTitle("选择开始日期");
        datePickerDialog.show();
    }

    private void showEndDateTimePicker() {
        hideKeyboard();
        final Calendar calendar = Calendar.getInstance();
        // Set initial time to start time + 1 hour as a suggestion
        calendar.setTimeInMillis(startTime);
        calendar.add(Calendar.HOUR, 1);

        DatePickerDialog datePickerDialog = new DatePickerDialog(this,
                new DatePickerDialog.OnDateSetListener() {
                    @Override
                    public void onDateSet(DatePicker view, int year, int month, int day) {
                        calendar.set(year, month, day);

                        TimePickerDialog timePickerDialog = new TimePickerDialog(MainActivity.this,
                                new TimePickerDialog.OnTimeSetListener() {
                                    @Override
                                    public void onTimeSet(TimePicker view, int hour, int minute) {
                                        calendar.set(Calendar.HOUR_OF_DAY, hour);
                                        calendar.set(Calendar.MINUTE, minute);
                                        endTime = calendar.getTimeInMillis();

                                        // 验证结束时间是否晚于开始时间
                                        if (endTime <= startTime) {
                                            Toast.makeText(MainActivity.this, "结束时间必须晚于开始时间", Toast.LENGTH_SHORT).show();
                                            showEndDateTimePicker(); // 重新选择
                                            return;
                                        }

                                        // 更新UI显示选择的时间
                                        updateTimeDisplay();

                                        // 显示确认对话框
                                        showConfirmationDialog();
                                    }
                                }, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true);
                        timePickerDialog.setTitle("选择结束时间");
                        timePickerDialog.show();
                    }
                }, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
        datePickerDialog.setOnShowListener(dialog -> {
            // 确保日期选择器获得焦点
            datePickerDialog.getButton(DialogInterface.BUTTON_POSITIVE).requestFocus();
        });
        datePickerDialog.setTitle("选择结束日期");
        datePickerDialog.show();
    }

    private void showConfirmationDialog() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
        String message = "确认上传以下时间范围内的照片吗？\n\n" +
                "开始时间: " + sdf.format(new Date(startTime)) + "\n" +
                "结束时间: " + sdf.format(new Date(endTime));

        new AlertDialog.Builder(this)
                .setTitle("确认查询")
                .setMessage(message)
                .setPositiveButton("确认", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // 用户确认，开始查询照片
                        queryPhotos();
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // 用户取消，可以重新选择时间或不做任何操作
                        Toast.makeText(MainActivity.this, "已取消查询", Toast.LENGTH_SHORT).show();
                    }
                })
                .setNeutralButton("重新选择", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // 用户想重新选择时间
                        showDateTimePicker();
                    }
                })
                .show();
    }

    private void updateTimeDisplay() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());

        if (startTime > 0) {
            startTimeText.setText("开始时间：" + sdf.format(new Date(startTime)));
        }

        if (endTime > 0) {
            endTimeText.setText("结束时间：" + sdf.format(new Date(endTime)));
        }
    }


    // 设置上传间隔
    private void setUploadInterval() {
        try {
            hideKeyboard();
            int minutes = Integer.parseInt(etUploadInterval.getText().toString());
            if (minutes <= 0) {
                showToast("请输入大于0的分钟数");
                return;
            }

            uploadIntervalMinutes = minutes;

            // 保存到SharedPreferences
            SharedPreferences.Editor editor = getSharedPreferences("UploadPrefs", MODE_PRIVATE).edit();
            editor.putInt("upload_interval", uploadIntervalMinutes);
            editor.apply();

            showToast("上传间隔已设置为: " + minutes + "分钟");

            // 如果定时上传正在运行，重新启动以应用新间隔
            if (isTimedUploadRunning) {
                stopTimedUpload();
                startTimedUpload();
            }
        } catch (NumberFormatException e) {
            showToast("请输入有效的数字");
        }
    }

    // 开始定时上传
    private void startTimedUpload() {
        if (uploadIntervalMinutes <= 0) {
            showToast("请先设置上传间隔");
            return;
        }

        if (isTimedUploadRunning) {
            showToast("定时上传已经在运行");
            return;
        }

        isTimedUploadRunning = true;
        btnStartTimedUpload.setEnabled(false);
        btnStopTimedUpload.setEnabled(true);
        etUploadInterval.setEnabled(false);
        btnSetInterval.setEnabled(false);


        // 设置定时任务
        timedUploadRunnable = new Runnable() {
            @Override
            public void run() {
                if (!isTimedUploadRunning) return;

                startUploadQueue();
                timedUploadHandler.postDelayed(this, uploadIntervalMinutes * 60 * 1000L);
            }
        };

        timedUploadHandler.postDelayed(timedUploadRunnable, uploadIntervalMinutes * 60 * 1000L);
        statusText.setText("定时上传已启动，间隔: " + uploadIntervalMinutes + "分钟");
    }

    // 停止定时上传
    private void stopTimedUpload() {
        if (!isTimedUploadRunning) return;

        isTimedUploadRunning = false;
        if (timedUploadRunnable != null) {
            timedUploadHandler.removeCallbacks(timedUploadRunnable);
        }

        btnStartTimedUpload.setEnabled(true);
        btnStopTimedUpload.setEnabled(false);
        etUploadInterval.setEnabled(true);
        btnSetInterval.setEnabled(true);

        statusText.setText("定时上传已停止");
    }


    private void uploadPhotoSync(String filePath, long time, Location location, String user,
                                 String audioPath, String project, String partId, String turbineId,
                                 String imageSource) {
        File file = new File(filePath);
        if (!file.exists()) {
            BackgroundToast.show(MainActivity.this, "文件不存在: " + filePath);
            return;
        }

        double latitude = location != null ? location.getLatitude() : 0;
        double longitude = location != null ? location.getLongitude() : 0;
        double altitude = location != null ? location.getAltitude() : 0;
        AudioEntity a = db.AudioDao().getAudioByPath(audioPath);
        try {

//            未设置部件id时调用批量上传项目文件的接口
            HttpUrl httpUrl = null;
            if (partId.isEmpty()) {
                httpUrl = HttpUrl.parse(RetrofitClient.BASE_URL + "/image/" + project + "/" + imageSource + "/upload-batch");
            } else {
                httpUrl = HttpUrl.parse(RetrofitClient.BASE_URL + "/image/" + imageSource + "/upload-batch/" + partId);
            }
            // 构建请求URL
            HttpUrl.Builder urlBuilder = httpUrl
                    .newBuilder()
                    .addQueryParameter("collectorId", UserId)
                    .addQueryParameter("collectorName", user)
                    .addQueryParameter("humidness", String.valueOf(Humidity))
                    .addQueryParameter("shootingDistance", String.valueOf(0)) // 根据需要设置实际值
                    .addQueryParameter("temperatureMax", String.valueOf(Temperator))
                    .addQueryParameter("temperatureMin", String.valueOf(Temperator))
                    .addQueryParameter("weather", Weather)
                    .addQueryParameter("windLevel", String.valueOf(0)); // 根据需要设置实际值


            // 创建请求体
            RequestBody requestBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("files", file.getName(),
                            RequestBody.create(file, MediaType.parse("image/*")))
                    .build();

            Request request = new Request.Builder()
                    .url(urlBuilder.build())
                    .post(requestBody)
                    .addHeader("Authorization", authToken)
                    .addHeader("Content-Type", "application/x-www-form-urlencoded")
                    .build();

            try (Response response = httpClient.newCall(request).execute()) {
                if (response.isSuccessful()) {
                    // 解析响应数据
                    String responseData = response.body().string();
                    JSONObject jsonResponse = new JSONObject(responseData);
                    JSONObject data = jsonResponse.optJSONObject("data");
                    String imageId = data != null ? data.optString("imageId") : "";
                    if (a != null) {
                        uploadAudio(imageId, audioPath, authToken);
                    }

                    BackgroundToast.show(
                            MainActivity.this,
                            "上传成功: " + response.code() + " " + filePath
                    );

                    executor.execute(() -> {
                        db.imageDao().insert(new ImageEntity(filePath, time,
                                latitude, longitude, altitude, user, audioPath,
                                project, partId, partName, turbineId, turbineName,
                                true, Temperator, Humidity, Weather, imageSource));
                    });
                } else {
                    BackgroundToast.show(MainActivity.this,
                            "上传失败: " + response.code() + " " + response.message()
                    );

                    if (isUploading) { // 只有主动上传时才重新加入队列
                        executor.execute(() -> {
                            db2.imageDao().insert(new ImageEntity(filePath, time,
                                    latitude, longitude, altitude, user, audioPath,
                                    project, partId, partName, turbineId, turbineName,
                                    true, Temperator, Humidity, Weather, imageSource));
                        });
                    }
                }
            }
        } catch (Exception e) {
            if (isUploading) { // 只有主动上传时才重新加入队列
                executor.execute(() -> {
                    db2.imageDao().insert(new ImageEntity(filePath, time,
                            latitude, longitude, altitude, user, audioPath,
                            project, partId, partName, turbineId, turbineName,
                            false, Temperator, Humidity, Weather, imageSource));
                });
            }
            BackgroundToast.show(MainActivity.this,
                    "上传失败: " + e.getMessage()
            );
        }
    }


    private void stopUploadQueue() {
        isUploading = false;
        dataManager.setUploading(isUploading);
        // 中断当前上传
        synchronized (uploadLock) {
            // 这里会中断当前上传
            uploadLock.notifyAll(); // 唤醒可能正在等待的上传线程
        }
        btnStopUpload.setEnabled(false);
        btnUploadQueue.setEnabled(true);
        // 更新状态显示
        runOnUiThread(() -> {
            statusText.setText(isTimedUploadRunning ? "定时上传已暂停" : "上传已停止");
            Toast.makeText(MainActivity.this, "上传队列已停止", Toast.LENGTH_SHORT).show();
        });
    }

    private void checkRecordPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
                != PackageManager.PERMISSION_GRANTED) {
            // 请求录音权限
            ActivityCompat.requestPermissions(
                    this,
                    new String[]{Manifest.permission.RECORD_AUDIO},
                    AUDIO_PERMISSION_REQUEST_CODE);
        } else {
            // 已经有录音权限，继续检查图片权限
            checkPermissionAndPickImage();
        }
    }


    private void initLocationManager() {
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        try {
            Location lastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            if (lastLocation != null) {
                lastKnownLocation = lastLocation;
                updateLocationText(lastLocation);
                dataManager.setLocation(lastLocation);
            }
        } catch (SecurityException e) {
            e.printStackTrace();
            BackgroundToast.show(MainActivity.this,
                    " 获取位置失败"
            );
        }
        locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                lastKnownLocation = location;
                Toast.makeText(MainActivity.this,
                        "位置更新: " + location.getLatitude() + ", " + location.getLongitude(),
                        Toast.LENGTH_SHORT).show();
                // 打印到Logcat
                dataManager.setLocation(lastKnownLocation);
                updateLocationText(lastKnownLocation);
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
            }

            @Override
            public void onProviderEnabled(String provider) {
            }

            @Override
            public void onProviderDisabled(String provider) {
            }
        };

        try {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "没有授予定位权限", Toast.LENGTH_SHORT).show();
                return;
            }
            locationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER,
                    60000,  // 5秒更新间隔
                    10,    // 10米距离变化
                    locationListener);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void updateLocationText(Location location) {
        runOnUiThread(() -> {
            if (location == null) {
                locationText.setText("当前位置: 无法获取位置信息");
                return;
            }
            String locationInfo = String.format(Locale.getDefault(),
                    "当前位置:\n纬度: %.6f\n经度: %.6f\n海拔: %.2f米\n精度: %.2f米\n更新时间: %s",
                    location.getLatitude(),
                    location.getLongitude(),
                    location.getAltitude(),
                    location.getAccuracy(),
                    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date(location.getTime())));

            locationText.setText(locationInfo);
        });
    }

    // 将位置转换为字符串用于打印
    private String locationToString(Location location) {
        return String.format(Locale.getDefault(),
                "纬度: %.6f, 经度: %.6f, 海拔: %.2f, 精度: %.2f, 时间: %s",
                location.getLatitude(),
                location.getLongitude(),
                location.getAltitude(),
                location.getAccuracy(),
                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date(location.getTime())));
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSION_REQUEST_StartMonitor_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限已授予，启动服务
                startMonitoring();
                statusText.setText("正在监听中");
            } else {
                // 权限被拒绝，显示提示
                Toast.makeText(this, "需要权限才能运行服务", Toast.LENGTH_SHORT).show();
            }
        } else if (requestCode == PERMISSIONS_REQUEST_CODE) {
            // 检查所有权限是否被授予
            boolean allPermissionsGranted = true;
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    allPermissionsGranted = false;
                    lastPhotoId = getLastPhotoId();
                    Log.e("最后一张照片值:", String.valueOf(lastPhotoId));
                    break;
                }
            }

            if (allPermissionsGranted) {
                // 所有权限都已授予，继续初始化位置管理器
                initLocationManager();
                haveInitalFloating = true;
                initFloatingActionButton();
            } else {
                // 处理权限被拒绝的情况
                handlePermissionDenial();
            }
        } else if (requestCode == REQUEST_VIDEO_PERMISSION) {
            boolean allGranted = true;
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    allGranted = false;
                    break;
                }
            }

            if (allGranted) {
                Toast.makeText(this, "媒体权限已授权", Toast.LENGTH_SHORT).show();

                queryVideos();
            } else {
                Toast.makeText(this, "需要媒体权限才能查询视频", Toast.LENGTH_SHORT).show();
            }


        }
        //通知权限
        else if (requestCode == NOTIFICATION_PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                BackgroundToast.show(this, "通知权限已开启");
            } else {
                Toast.makeText(this, "通知权限被拒绝，无法显示录音状态", Toast.LENGTH_SHORT).show();
            }
        } else if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 位置权限已授予，继续检查图片权限
                checkRecordPermission();
                initLocationManager();
                Toast.makeText(this, "位置权限已授予", Toast.LENGTH_SHORT).show();
            } else {
                // 位置权限被拒绝，关闭开关
                switchMonitor.setChecked(false);
                Toast.makeText(this, "需要位置权限才能获取位置信息", Toast.LENGTH_SHORT).show();
            }
        } else if (requestCode == AUDIO_PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 录音权限已授予，继续检查位置权限
                checkPermissionAndPickImage();
                Toast.makeText(this, "语音权限已授予", Toast.LENGTH_SHORT).show();
            } else {
                // 录音权限被拒绝，关闭开关
                switchMonitor.setChecked(false);
                Toast.makeText(this, "需要录音权限才能录制语音", Toast.LENGTH_SHORT).show();
            }
        }
        //图片权限
        else if (requestCode == PERMISSION_REQUEST_CODE) {

            boolean allGranted = true;
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    allGranted = false;
                    break;
                }
            }

            if (allGranted) {
                Toast.makeText(this, "媒体权限已授与", Toast.LENGTH_SHORT).show();

                startMonitoring();
            } else {
                switchMonitor.setChecked(false);
                Toast.makeText(this, "需要媒体权限以选择图片", Toast.LENGTH_SHORT).show();


                if (shouldShowRequestPermissionRationale(permissions)) {
                    showPermissionExplanationDialog(() -> {
                        // 重新请求权限
                        requestPermissions(permissions);
                    });
                }
            }
        }

    }

    private void handlePermissionDenial() {
        // 检查哪些关键权限被拒绝
        boolean showRationale = false;

        // 检查是否有权限被永久拒绝（用户勾选了"不再询问"）
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            for (String permission : new String[]{
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.RECORD_AUDIO,
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.POST_NOTIFICATIONS}) {
                if (!shouldShowRequestPermissionRationale(permission)
                        && ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                    showRationale = true;
                    break;
                }
            }
        } else {
            for (String permission : new String[]{
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.RECORD_AUDIO,
                    Manifest.permission.ACCESS_FINE_LOCATION}) {
                if (!shouldShowRequestPermissionRationale(permission)
                        && ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                    showRationale = true;
                    break;
                }
            }
        }

        if (showRationale) {
            // 显示解释为什么需要权限，并引导用户去设置页面
            showPermissionExplanationDialog();
        } else {
            // 部分权限被拒绝，但用户没有选择"不再询问"
            Toast.makeText(this, "部分功能可能无法正常使用", Toast.LENGTH_SHORT).show();
            // 仍然尝试初始化位置管理器（如果位置权限被授予）
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) {
                initLocationManager();
            }
        }
    }

    // 显示权限解释对话框
    private void showPermissionExplanationDialog() {
        new AlertDialog.Builder(this)
                .setTitle("需要权限")
                .setMessage("某些功能需要权限才能正常工作。请前往设置授予权限。")
                .setPositiveButton("去设置", (dialog, which) -> {
                    // 跳转到应用设置页面
                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                    Uri uri = Uri.fromParts("package", getPackageName(), null);
                    intent.setData(uri);
                    startActivity(intent);
                })
                .setNegativeButton("取消", null)
                .show();
    }

    private void checkPermissionAndPickImage() {
        String[] permissions;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { // Android 14+
            permissions = new String[]{
                    Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VIDEO
            };
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // Android 13
            permissions = new String[]{Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_VIDEO};
        } else { // Android 12-
            permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE};
        }

        if (checkAnyPermissionGranted(permissions)) {
            try {
                startMonitoring();
            } catch (Exception e) {
                dataManager.setOthermsg(e.toString());
                BackgroundToast.show(this, "监听失败");
            }
        } else {
            requestPermissions(permissions);
        }
    }

    private boolean checkAnyPermissionGranted(String[] permissions) {
        for (String perm : permissions) {
            if (ContextCompat.checkSelfPermission(this, perm) == PackageManager.PERMISSION_GRANTED) {
                return true;
            }
        }
        return false;
    }

    private void requestPermissions(String[] permissions) {
        if (shouldShowRequestPermissionRationale(permissions)) {
            showPermissionExplanationDialog(() ->
                    ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE));
        } else {
            ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);
        }
    }

    private boolean shouldShowRequestPermissionRationale(String[] permissions) {
        for (String perm : permissions) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, perm)) {
                return true;
            }
        }
        return false;
    }

    private void openAppSettings() {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.fromParts("package", getPackageName(), null));
        startActivity(intent);
    }

    private void showPermissionExplanationDialog(Runnable onContinue) {
        new AlertDialog.Builder(this)
                .setTitle("需要权限")
                .setMessage("此功能需要访问图片权限以监控相册变化")
                .setPositiveButton("继续", (dialog, which) -> onContinue.run())
                .setNegativeButton("取消", null)
                .show();
    }

    private void showHistory(AppDatabase database, String title, String deleteBtnText, String deleteMessage) {
        new Thread(() -> {
            List<ImageEntity> history = database.imageDao().getAll();
            runOnUiThread(() -> {
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle(title);

                LinearLayout mainContainer = createDialogContainer(deleteBtnText, database, deleteMessage, history);
                ScrollView scrollContainer = createScrollContainer(history, database);

                mainContainer.addView(scrollContainer);
                builder.setView(mainContainer);
                builder.setPositiveButton("关闭", null);

                AlertDialog dialog = builder.create();
                updateCurrentDialog(database, dialog);
                dialog.show();
            });
        }).start();
    }


    private LinearLayout createDialogContainer(String deleteBtnText, AppDatabase database, String deleteMessage, List<ImageEntity> history) {
        LinearLayout mainContainer = new LinearLayout(this);
        mainContainer.setOrientation(LinearLayout.VERTICAL);

        // 顶部按钮布局
        LinearLayout buttonLayout = new LinearLayout(this);
        buttonLayout.setOrientation(LinearLayout.HORIZONTAL);
        buttonLayout.setLayoutParams(new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));

        // 批量删除按钮
        Button batchDeleteButton = new Button(this);
        batchDeleteButton.setText("批量删除");
        batchDeleteButton.setOnClickListener(v -> showBatchDeleteDialog(database, history));
        buttonLayout.addView(batchDeleteButton);

        // 时间段删除按钮
        Button timeRangeDeleteButton = new Button(this);
        timeRangeDeleteButton.setText("时间段删除");
        timeRangeDeleteButton.setOnClickListener(v -> showTimeRangeDeleteDialog(database));
        buttonLayout.addView(timeRangeDeleteButton);

        // 删除所有按钮
        Button deleteAllButton = new Button(this);
        deleteAllButton.setText(deleteBtnText);
        deleteAllButton.setOnClickListener(v -> confirmDelete(database, deleteMessage));
        buttonLayout.addView(deleteAllButton);

        mainContainer.addView(buttonLayout);

        return mainContainer;
    }


    private ScrollView createScrollContainer(List<ImageEntity> history, AppDatabase database) {
        ScrollView scrollContainer = new ScrollView(this);
        LinearLayout contentContainer = new LinearLayout(this);
        contentContainer.setOrientation(LinearLayout.VERTICAL);

        if (history.isEmpty()) {
            addEmptyView(contentContainer, database);
        } else {
            addHistoryItems(contentContainer, history, database);
        }

        scrollContainer.addView(contentContainer);
        return scrollContainer;
    }

    private void addEmptyView(LinearLayout contentContainer, AppDatabase database) {
        TextView emptyText = new TextView(this);
        emptyText.setText(database == db ? "暂无历史记录" : "暂无缓存记录");
        contentContainer.addView(emptyText);
    }

    private void addHistoryItems(LinearLayout contentContainer, List<ImageEntity> history, AppDatabase database) {
        for (ImageEntity item : history) {
            View itemView = LayoutInflater.from(this).inflate(R.layout.item_history, contentContainer, false);

            // 添加复选框
            CheckBox checkBox = new CheckBox(this);
            checkBox.setTag(item.id); // 使用记录的ID作为tag

            LinearLayout itemLayout = (LinearLayout) itemView.findViewById(R.id.item_layout);
            if (itemLayout != null) {
                itemLayout.addView(checkBox, 0); // 将复选框添加到最前面
            }

            setupItemView(itemView, item);
            contentContainer.addView(itemView);
        }
    }

    private void showBatchDeleteDialog(AppDatabase database, List<ImageEntity> history) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("批量删除");

        // 获取所有复选框的选中状态
        List<Integer> selectedIds = new ArrayList<>();
        ViewGroup container = (ViewGroup) ((ViewGroup) currentDialog.getWindow().getDecorView()).getChildAt(0);
        findSelectedCheckBoxes(container, selectedIds);

        if (selectedIds.isEmpty()) {
            builder.setMessage("请先勾选要删除的项");
            builder.setPositiveButton("确定", null);
        } else {
            builder.setMessage("确定要删除选中的 " + selectedIds.size() + " 项记录吗？");
            builder.setPositiveButton("删除", (dialog, which) -> {
                deleteSelectedRecords(database, selectedIds);
            });
            builder.setNegativeButton("取消", null);
        }

        builder.show();
    }

    // 查找选中的复选框
    private void findSelectedCheckBoxes(ViewGroup container, List<Integer> selectedIds) {
        for (int i = 0; i < container.getChildCount(); i++) {
            View child = container.getChildAt(i);
            if (child instanceof ViewGroup) {
                findSelectedCheckBoxes((ViewGroup) child, selectedIds);
            } else if (child instanceof CheckBox) {
                CheckBox checkBox = (CheckBox) child;
                if (checkBox.isChecked()) {
                    selectedIds.add((Integer) checkBox.getTag());
                }
            }
        }
    }

    // 删除选中的记录
    private void deleteSelectedRecords(AppDatabase database, List<Integer> selectedIds) {
        executor.execute(() -> {
            database.imageDao().deleteByIds(selectedIds);
            runOnUiThread(() -> {
                Toast.makeText(this, "已删除选中的 " + selectedIds.size() + " 项记录", Toast.LENGTH_SHORT).show();
                dismissCurrentDialog(database);
            });
        });
    }

    // 显示时间段删除对话框
    // 显示时间段删除对话框 - 优化后的版本
    private void showTimeRangeDeleteDialog(AppDatabase database) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("按时间段删除");

        // 使用ScrollView确保内容可滚动
        ScrollView scrollView = new ScrollView(this);
        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.setPadding(32, 32, 32, 32); // 增加内边距

        // 开始时间部分
        TextView startText = new TextView(this);
        startText.setText("开始时间:");
        startText.setTextSize(18);
        layout.addView(startText);

        // 开始日期和时间选择器
        LinearLayout startTimeLayout = new LinearLayout(this);
        startTimeLayout.setOrientation(LinearLayout.VERTICAL);

        final DatePicker startDatePicker = new DatePicker(this);
        startDatePicker.setCalendarViewShown(false); // 使用spinner模式更紧凑
        startTimeLayout.addView(startDatePicker);

        final TimePicker startTimePicker = new TimePicker(this);
        startTimePicker.setIs24HourView(true);
        startTimeLayout.addView(startTimePicker);

        layout.addView(startTimeLayout);

        // 添加分隔空间
        View space = new View(this);
        space.setLayoutParams(new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT, 32));
        layout.addView(space);

        // 结束时间部分
        TextView endText = new TextView(this);
        endText.setText("结束时间:");
        endText.setTextSize(18);
        layout.addView(endText);

        // 结束日期和时间选择器
        LinearLayout endTimeLayout = new LinearLayout(this);
        endTimeLayout.setOrientation(LinearLayout.VERTICAL);

        final DatePicker endDatePicker = new DatePicker(this);
        endDatePicker.setCalendarViewShown(false);
        endTimeLayout.addView(endDatePicker);

        final TimePicker endTimePicker = new TimePicker(this);
        endTimePicker.setIs24HourView(true);
        endTimeLayout.addView(endTimePicker);

        layout.addView(endTimeLayout);

        scrollView.addView(layout);
        builder.setView(scrollView);

        builder.setPositiveButton("删除", (dialog, which) -> {
            // 获取开始时间
            Calendar startCal = Calendar.getInstance();
            startCal.set(startDatePicker.getYear(),
                    startDatePicker.getMonth(),
                    startDatePicker.getDayOfMonth(),
                    startTimePicker.getHour(),
                    startTimePicker.getMinute(),
                    0);
            long startTime = startCal.getTimeInMillis();

            // 获取结束时间
            Calendar endCal = Calendar.getInstance();
            endCal.set(endDatePicker.getYear(),
                    endDatePicker.getMonth(),
                    endDatePicker.getDayOfMonth(),
                    endTimePicker.getHour(),
                    endTimePicker.getMinute(),
                    59);
            long endTime = endCal.getTimeInMillis();

            if (startTime > endTime) {
                Toast.makeText(this, "开始时间不能晚于结束时间", Toast.LENGTH_SHORT).show();
                return;
            }

            confirmTimeRangeDelete(database, startTime, endTime);
        });

        builder.setNegativeButton("取消", null);

        // 创建并显示对话框
        AlertDialog dialog = builder.create();

        // 设置对话框大小
        Window window = dialog.getWindow();
        if (window != null) {
            WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
            lp.copyFrom(window.getAttributes());
            lp.width = WindowManager.LayoutParams.MATCH_PARENT;
            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
            window.setAttributes(lp);
        }

        dialog.show();
    }

    // 确认时间段删除
    private void confirmTimeRangeDelete(AppDatabase database, long startTime, long endTime) {
        new AlertDialog.Builder(this)
                .setTitle("确认删除")
                .setMessage(String.format("确定要删除 %s 至 %s 的所有记录吗?",
                        sdf.format(new Date(startTime)),
                        sdf.format(new Date(endTime))))
                .setPositiveButton("删除", (d, w) -> deleteRecordsByTimeRange(database, startTime, endTime))
                .setNegativeButton("取消", null)
                .show();
    }

    // 删除时间段内的记录
    private void deleteRecordsByTimeRange(AppDatabase database, long startTime, long endTime) {
        executor.execute(() -> {
            int deletedCount = database.imageDao().deleteByTimeRange(startTime, endTime);
            runOnUiThread(() -> {
                Toast.makeText(this, "已删除 " + deletedCount + " 条记录", Toast.LENGTH_SHORT).show();
                dismissCurrentDialog(database);
            });
        });
    }

    private void setupItemView(View itemView, ImageEntity item) {
        ImageView iv = itemView.findViewById(R.id.iv_thumbnail);
        TextView tv = itemView.findViewById(R.id.tv_info);

        executor.execute(() -> loadThumbnail(iv, item.path));

        tv.setText(String.format(
                Locale.US,
                "时间: %s\n" +
                        "路径: %s\n" +
                        "纬度: %.6f\n" +   // 保留6位小数
                        "经度: %.6f\n" +
                        "高度: %.2f 米\n" + // 保留2位小数
                        "参与人名: %s\n" +
                        "项目名字:%s\n" +
                        "机组号:%s\n" +
                        "叶片号:%s\n" +
                        "图片来源:%s\n",

                sdf.format(new Date(item.time)),  // 时间
                item.path,                       // 路径
                item.latitude,                    // 纬度
                item.longitude,                  // 经度
                item.altitude,                   // 高度（单位：米）
                item.user,// 用户信息
                projectName,
                item.turbineName,
                item.partName,
                item.imageSource

        ));
        itemView.setOnClickListener(v -> openFullImage(item.path));
    }

    private void loadThumbnail(ImageView iv, String path) {
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = DECODE_SAMPLE_SIZE;
            Bitmap src = BitmapFactory.decodeFile(path, options);
            if (src != null) {
                Bitmap thumbnail = Bitmap.createScaledBitmap(src, THUMBNAIL_SIZE, THUMBNAIL_SIZE, true);
                runOnUiThread(() -> iv.setImageBitmap(thumbnail));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void confirmDelete(AppDatabase database, String message) {

        new AlertDialog.Builder(this)
                .setTitle("确认删除")
                .setMessage(message)
                .setPositiveButton("删除", (d, w) -> deleteAllRecords(database))
                .setNegativeButton("取消", null)
                .show();

    }


    private void deleteAllRecords(AppDatabase database) {
        executor.execute(() -> {
            database.imageDao().deleteAll();
            runOnUiThread(() -> {
                Toast.makeText(this, "已删除所有记录", Toast.LENGTH_SHORT).show();
                dismissCurrentDialog(database);
            });
        });
    }

    private void updateCurrentDialog(AppDatabase database, AlertDialog dialog) {
        if (database == db) {
            currentDialog = dialog;
        } else {
            currentDialog2 = dialog;
        }
    }

    private void dismissCurrentDialog(AppDatabase database) {
        if (database == db && currentDialog != null && currentDialog.isShowing()) {
            currentDialog.dismiss();
        } else if (database == db2 && currentDialog2 != null && currentDialog2.isShowing()) {
            currentDialog2.dismiss();
        }
    }

    private boolean isNetworkAvailable() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        if (cm == null) return false;

        NetworkCapabilities capabilities = cm.getNetworkCapabilities(cm.getActiveNetwork());
        return capabilities != null &&
                (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
                        capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
                        capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET));
    }

    private void stopMonitoring() {
        Intent serviceIntent = new Intent(this, PhotoMonitoringService.class);
        stopService(serviceIntent);
        statusText.setText("当前状态：未监听");
        switchMonitor.setChecked(false);
    }

    private void startUploadQueue() {
        if (isUploading) {
            Toast.makeText(this, "上传正在进行中", Toast.LENGTH_SHORT).show();
            return;
        }

        executor.execute(() -> {
            isUploading = true;
            dataManager.setUploading(isUploading);
            runOnUiThread(() -> {
                btnUploadQueue.setEnabled(false);
                btnStopUpload.setEnabled(true);
                statusText.setText("正在上传缓存队列..." + (isTimedUploadRunning ? "(定时上传)" : ""));
            });

            try {
                while (isUploading) {
                    List<ImageEntity> queue = db2.imageDao().getAll();
                    if (queue.isEmpty()) {
                        break;
                    }

                    for (ImageEntity image : queue) {
                        if (!isUploading) break;
                        synchronized (uploadLock) {
                            uploadPhotoSync(image.path, image.time,
                                    new Location("") {{
                                        setLatitude(image.latitude);
                                        setLongitude(image.longitude);
                                        setAltitude(image.altitude);
                                    }},
                                    image.user, image.audioPath, image.project, image.partId, image.turbineId, image.imageSource);
                        }

                        if (isUploading) {
                            db2.imageDao().delete(image);
                        }
                    }
                }
            } finally {
                runOnUiThread(() -> {
                    btnUploadQueue.setEnabled(true);
                    btnStopUpload.setEnabled(false);
                    String status = isUploading ?
                            (isTimedUploadRunning ? "定时上传完成" : "手动上传完成") :
                            "上传已终止";
                    statusText.setText(status);
                });
                isUploading = false;
                dataManager.setUploading(isUploading);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (updateReceiver != null) {
            unregisterReceiver(updateReceiver);
        }
        stopMonitoring();
        executor.shutdown();
        if (httpClient != null) {
            httpClient.dispatcher().executorService().shutdown();
            httpClient.connectionPool().evictAll();
        }
        stopTimedUpload();
        if (!executor.isTerminated()) {
            executor.shutdownNow();
        }
        // 移除悬浮球
        if (floatingActionButton != null) {
            WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
            windowManager.removeView(floatingActionButton);
        }
        if (isRecording)
            stopVoiceRecording();

    }


    private String getCurrentUser() {
        String user = name;
        // 如果用户没有输入信息，则使用设备型号作为默认值
        if (user == "-1") {
            user = currentUsername;
        }
        return user;
    }

    private void openFullImage(String imagePath) {
        File file = new File(imagePath);
        Uri uri = FileProvider.getUriForFile(
                this,
                getPackageName() + ".provider",
                file
        );

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(uri, "image/*");
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        startActivity(intent);
    }


    private void uploadAudio(String imageId, String audioPath, String token) {
        // 1. 参数校验（在调用线程执行，避免不必要的后台任务）
        if (audioPath == null || audioPath.equals("0")) {
            BackgroundToast.show(MainActivity.this, "文件路径为空");
            return;
        }

        File audioFile = new File(audioPath);
        if (!audioFile.exists()) {
            BackgroundToast.show(MainActivity.this, "文件不存在");
            return;
        }

        // 2. 在后台线程执行上传逻辑
        executor.execute(() -> {
            // 3. 构建请求体（已在后台线程）
            RequestBody requestBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("file", audioFile.getName(),
                            RequestBody.create(audioFile, MediaType.parse("audio/*")))
                    .build();

            // 4. 构建请求
            Request.Builder requestBuilder = new Request.Builder()
                    .url(RetrofitClient.BASE_URL + "/audio/upload/" + imageId)
                    .post(requestBody);

            if (token != null && !token.isEmpty()) {
                requestBuilder.addHeader("Authorization", token);
            }

            // 5. 同步执行请求（try-with-resources 自动关闭 Response）
            try (Response response = httpClient.newCall(requestBuilder.build()).execute()) {
                String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
                        .format(new Date());

                if (response.isSuccessful()) {
                    // 上传成功
                    db.AudioDao().deleteByPath(audioPath);
                    db2.AudioDao().insert(new AudioEntity(audioPath, imageId, currentTime, true));
                    BackgroundToast.show(MainActivity.this, "录音上传成功: " + imageId);
                } else {
                    // 上传失败（HTTP 错误）
                    db.AudioDao().insert(new AudioEntity(audioPath, imageId, currentTime, false));
                    BackgroundToast.show(MainActivity.this,
                            "录音上传失败: " + response.code() + " " + response.message());
                }
            } catch (IOException e) {
                // 网络异常
                String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
                        .format(new Date());
                db.AudioDao().insert(new AudioEntity(audioPath, imageId, currentTime, false));
                BackgroundToast.show(MainActivity.this, "录音上传失败: " + e.getMessage());
            }
        });
    }

    private long getLastPhotoId() {
        long id = -1;
        Cursor cursor = getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                new String[]{"MAX(" + MediaStore.Images.Media._ID + ")"},
                null,
                null,
                null
        );

        if (cursor != null && cursor.moveToFirst()) {
            id = cursor.getLong(0);  // MAX(_ID) 的结果在索引 0
            cursor.close();
        }
        return id;
    }


}