using System;
using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using System.Net;
using Updater.Helpers;

namespace Updater
{
    public partial class FormUpdate : Form
    {
        private readonly WebClient _webClient;
        private bool _isBusy;
        private bool _abort;
        readonly string[] _args;

        public FormUpdate(string[] args)
        {
            InitializeComponent();

            _webClient = new WebClient();
            _webClient.DownloadFileCompleted += DownloadFileCompleted;
            _webClient.DownloadProgressChanged += DownloadProgressChanged;

            _args = args;
        }

        private void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            _isBusy = false;
            if (_abort)
                return;

            if (e.Error == null)
            {
                progressBar1.Value = 0;
                backgroundWorker1.RunWorkerAsync();
            }
            else
            {
                MessageBox.Show("Błąd aktualizacji oprogramowania: " + e.Error.Message, "Aktualizacja 001", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Close();
            }
        }

        private void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            Refresh();
            progressBar1.Value = e.ProgressPercentage;
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            _isBusy = false;
            _abort = true;
            _webClient.CancelAsync();
            Close();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(_isBusy || backgroundWorker1.IsBusy)
                e.Cancel = true;
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                ZipHelper.Extract(Environment.CurrentDirectory + "\\" + _args[0] + ".zip", Environment.CurrentDirectory, false);

                MessageBox.Show("Zakończono aktualizację oprogramowania.", "Aktualizacja", MessageBoxButtons.OK, MessageBoxIcon.Information);
                System.Diagnostics.Process.Start(_args[0] + ".exe");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Aktualizacja 003", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            _isBusy = false;
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (!Visible || WindowState != FormWindowState.Normal) return;

            if (e.ProgressPercentage < progressBar1.Maximum) progressBar1.Value = e.ProgressPercentage;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Close();
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            try
            {
                if (_args.Length < 2)
                    throw new ApplicationException("Błędne wywołanie programu!");

                _isBusy = true;
                progressBar1.Value = 0;
                string s1 = Environment.CurrentDirectory;
                s1 += "\\" + _args[0] + ".zip";

                if (File.Exists(s1))
                    File.Delete(s1);
                
                Refresh();
                RenameTarget(Environment.CurrentDirectory + Path.DirectorySeparatorChar + _args[0] + ".exe");
                Refresh();

                _webClient.DownloadFileAsync(new Uri(_args[1]), s1);
            }
            catch (UriFormatException ex)
            {
                MessageBox.Show(ex.Message, "Aktualizacja 004", MessageBoxButtons.OK, MessageBoxIcon.Error);
                _isBusy = false;
                Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Aktualizacja 005", MessageBoxButtons.OK, MessageBoxIcon.Error);
                _isBusy = false;
                Close();
            }
        }

        private void RenameTarget(string file)
        {
            if(!File.Exists(file)) return;

            bool renamed = false;
            int attemps = 0;
            while (!renamed)
            {
                try
                {
                    File.Copy(file, file + ".old", true);
                    File.Delete(file);
                    renamed = true;
                }
                catch (Exception)
                {
                    if (attemps > 3)
                        throw;
                    
                    attemps++;
                    Refresh();
                    Thread.Sleep(1000);
                }
            }
        }
    }
}