defmodule DaProductAppWeb.AppPackageController do use DaProductAppWeb, :controller require Logger alias DaProductApp.TerminalManagement alias DaProductApp.TerminalManagement.AppPackageService alias DaProductApp.Workers.AppPackageWorker @doc """ Deploy app package to a single device immediately. """ def deploy_package(conn, %{"device_serial" => device_serial, "package_id" => package_id} = params) do config_id = params["config_id"] deployment_options = params["deployment_options"] || %{} case AppPackageService.deploy_package_to_device(device_serial, package_id, config_id) do {:ok, message} -> json(conn, %{ success: true, message: message, device_serial: device_serial, package_id: package_id }) {:error, reason} -> conn |> put_status(:bad_request) |> json(%{ success: false, error: reason, device_serial: device_serial, package_id: package_id }) end end @doc """ Schedule app package deployment for later execution. """ def schedule_package_deployment(conn, %{"device_serial" => device_serial, "package_id" => package_id} = params) do config_id = params["config_id"] schedule_at = parse_schedule_time(params["schedule_at"]) case AppPackageWorker.schedule_package_deployment(device_serial, package_id, config_id, schedule_at: schedule_at) do {:ok, job} -> json(conn, %{ success: true, message: "App package deployment job scheduled successfully", job_id: job.id, device_serial: device_serial, package_id: package_id, scheduled_at: schedule_at }) {:error, changeset} -> conn |> put_status(:bad_request) |> json(%{ success: false, error: "Failed to schedule deployment job", details: changeset }) end end @doc """ Deploy app package to multiple devices. """ def batch_deploy_package(conn, %{"device_serials" => device_serials, "package_id" => package_id} = params) do config_id = params["config_id"] schedule_at = parse_schedule_time(params["schedule_at"]) case AppPackageWorker.schedule_batch_package_deployment(device_serials, package_id, config_id, schedule_at: schedule_at) do {:ok, job} -> json(conn, %{ success: true, message: "Batch app package deployment job scheduled successfully", job_id: job.id, device_count: length(device_serials), package_id: package_id, scheduled_at: schedule_at }) {:error, changeset} -> conn |> put_status(:bad_request) |> json(%{ success: false, error: "Failed to schedule batch deployment job", details: changeset }) end end @doc """ Rollback app package to previous version. """ def rollback_package(conn, %{"device_serial" => device_serial, "target_version" => target_version} = params) do case AppPackageService.rollback_package(device_serial, target_version) do {:ok, message} -> json(conn, %{ success: true, message: message, device_serial: device_serial, target_version: target_version }) {:error, reason} -> conn |> put_status(:bad_request) |> json(%{ success: false, error: reason, device_serial: device_serial }) end end @doc """ Schedule app package rollback for later execution. """ def schedule_package_rollback(conn, %{"device_serial" => device_serial, "target_version" => target_version} = params) do schedule_at = parse_schedule_time(params["schedule_at"]) case AppPackageWorker.schedule_package_rollback(device_serial, target_version, schedule_at: schedule_at) do {:ok, job} -> json(conn, %{ success: true, message: "App package rollback job scheduled successfully", job_id: job.id, device_serial: device_serial, target_version: target_version, scheduled_at: schedule_at }) {:error, changeset} -> conn |> put_status(:bad_request) |> json(%{ success: false, error: "Failed to schedule rollback job", details: changeset }) end end @doc """ Get deployment status for a specific device and package. """ def get_deployment_status(conn, %{"device_serial" => device_serial} = params) do config_id = params["config_id"] package_id = params["package_id"] case TerminalManagement.get_device_deployment_status(device_serial, config_id, package_id) do nil -> conn |> put_status(404) |> json(%{status: "error", message: "Deployment status not found"}) status -> conn |> put_status(200) |> json(%{ status: "success", data: %{ device_serial: status.device_sn, package_id: package_id, config_id: config_id, status: status.status, update_result: status.update_result, remark: status.remark, pushed_time: status.pushed_time, finish_time: status.finish_time, vendor: status.vendor, model: status.model, app_version: status.app_version, data_version: status.data_version, system_version: status.system_version } }) end end @doc """ Get comprehensive package deployment statistics. """ def get_deployment_statistics(conn, _params) do stats = TerminalManagement.get_app_deployment_statistics() conn |> put_status(200) |> json(%{ status: "success", data: stats }) end @doc """ Get package compatibility check for devices. """ def check_package_compatibility(conn, %{"package_id" => package_id, "device_serials" => device_serials}) do compatibility_results = Enum.map(device_serials, fn device_serial -> case TerminalManagement.check_package_compatibility(package_id, device_serial) do {:ok, compatibility} -> %{ device_serial: device_serial, compatible: true, compatibility: compatibility } {:error, reason} -> %{ device_serial: device_serial, compatible: false, reason: reason } end end) compatible_count = Enum.count(compatibility_results, & &1.compatible) json(conn, %{ success: true, total_devices: length(device_serials), compatible_devices: compatible_count, incompatible_devices: length(device_serials) - compatible_count, results: compatibility_results }) end defp parse_schedule_time(nil), do: DateTime.utc_now() defp parse_schedule_time(schedule_str) when is_binary(schedule_str) do case DateTime.from_iso8601(schedule_str) do {:ok, datetime, _} -> datetime {:error, _} -> DateTime.utc_now() end end defp parse_schedule_time(%DateTime{} = datetime), do: datetime defp parse_schedule_time(_), do: DateTime.utc_now() end