// Copyright 2022 pyke.io
//           2019-2021 Tauri Programme within The Commons Conservancy
//                     [https://tauri.studio/]
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{
	env,
	fs::{self, write},
	path::PathBuf,
	process::{Command, Stdio}
};

use anyhow::Context;

use super::{super::common, app, icon::create_icns_file};
use crate::{bundle::Bundle, PackageType::MacOsBundle, Settings};

/// Bundles the project.
/// Returns a vector of PathBuf that shows where the DMG was created.
pub fn bundle_project(settings: &Settings, bundles: &[Bundle]) -> crate::Result<Vec<PathBuf>> {
	// generate the .app bundle if needed
	if bundles.iter().filter(|bundle| bundle.package_type == MacOsBundle).count() == 0 {
		app::bundle_project(settings)?;
	}

	// get the target path
	let output_path = settings.project_out_directory().join("bundle/dmg");
	let package_base_name = format!(
		"{}_{}_{}",
		settings.main_binary_name(),
		settings.version_string(),
		match settings.binary_arch() {
			"x86_64" => "x64",
			other => other
		}
	);
	let dmg_name = format!("{}.dmg", &package_base_name);
	let dmg_path = output_path.join(&dmg_name);

	let product_name = settings.main_binary_name();
	let bundle_file_name = format!("{}.app", product_name);
	let bundle_dir = settings.project_out_directory().join("bundle/macos");

	let support_directory_path = output_path.join("support");
	if output_path.exists() {
		fs::remove_dir_all(&output_path).with_context(|| format!("Failed to remove old {}", dmg_name))?;
	}
	fs::create_dir_all(&support_directory_path).with_context(|| format!("Failed to create output directory at {:?}", support_directory_path))?;

	// create paths for script
	let bundle_script_path = output_path.join("bundle_dmg.sh");

	common::print_bundling(format!("{:?}", &dmg_path).as_str())?;

	// write the scripts
	write(&bundle_script_path, include_str!("templates/dmg/bundle_dmg"))?;
	write(support_directory_path.join("template.applescript"), include_str!("templates/dmg/template.applescript"))?;
	write(support_directory_path.join("eula-resources-template.xml"), include_str!("templates/dmg/eula-resources-template.xml"))?;

	// chmod script for execution
	Command::new("chmod")
		.arg("777")
		.arg(&bundle_script_path)
		.current_dir(&output_path)
		.stdout(Stdio::piped())
		.stderr(Stdio::piped())
		.output()
		.expect("Failed to chmod script");

	let mut args = vec![
		"--volname",
		&product_name,
		"--icon",
		&product_name,
		"180",
		"170",
		"--app-drop-link",
		"480",
		"170",
		"--window-size",
		"660",
		"400",
		"--hide-extension",
		&bundle_file_name,
	];

	let icns_icon_path = create_icns_file(&output_path, &settings)?.map(|path| path.to_string_lossy().to_string());
	if let Some(icon) = &icns_icon_path {
		args.push("--volicon");
		args.push(icon);
	}

	#[allow(unused_assignments)]
	let mut license_path_ref = "".to_string();
	if let Some(license_path) = &settings.macos().license {
		args.push("--eula");
		license_path_ref = env::current_dir()?.join(license_path).to_string_lossy().to_string();
		args.push(&license_path_ref);
	}

	// Issue #592 - Building MacOS dmg files on CI
	// https://github.com/tauri-apps/tauri/issues/592
	if let Some(value) = env::var_os("CI") {
		if value == "true" {
			args.push("--skip-jenkins");
		}
	}

	// execute the bundle script
	let mut cmd = Command::new(&bundle_script_path);
	cmd.current_dir(bundle_dir.clone())
		.args(args)
		.args(vec![dmg_name.as_str(), bundle_file_name.as_str()]);

	common::print_info("running bundle_dmg.sh")?;
	common::execute_with_verbosity(&mut cmd, &settings).map_err(|_| {
		crate::Error::ShellScriptError(format!(
			"error running bundle_dmg.sh{}",
			if settings.is_verbose() { "" } else { ", try running with --verbose to see command output" }
		))
	})?;

	fs::rename(bundle_dir.join(dmg_name), dmg_path.clone())?;

	// Sign DMG if needed
	if let Some(identity) = &settings.macos().signing_identity {
		super::sign::sign(dmg_path.clone(), identity, &settings, false)?;
	}
	Ok(vec![dmg_path])
}
