#  _____                   _         
# |  __ \                 ( )        
# | |  | |_   _ _ __   ___|/ ___     
# | |  | | | | | '_ \ / _ \ / __|    
# | |__| | |_| | | | |  __/ \__ \    
# |_____/ \__,_|_| |_|\___| |___/    
# |  __ \      / _|          | | |   
# | |  | | ___| |_ __ _ _   _| | |_  
# | |  | |/ _ \  _/ _` | | | | | __| 
# | |__| |  __/ || (_| | |_| | | |_  
# |_____/ \___|_| \__,_|\__,_|_|\__| 
# |  __ \        | |         | |     
# | |__) | __ ___| |_   _  __| | ___ 
# |  ___/ '__/ _ \ | | | |/ _` |/ _ \
# | |   | | |  __/ | |_| | (_| |  __/
# |_|   |_|  \___|_|\__,_|\__,_|\___|
#

if os@name == "windows" {
    let ls = dir ~> fs@ls dir | join "\n" | echo;
    let rm = fs@rm;
    let cp = fs@cp;
    let mv = fs@mv;
    let mkdir = fs@mkdir;
    let rmdir = fs@rmdir;

    let cat = fs@read;
}

console@title "Dune";

let donate = _ ~> {
        echo "                     ┌──────Wild Dune Shrew──────┐
                      Hello, how is Dune working
                      for you so far? If you like
                      it, consider starring our
                      GitHub page and donating!";
        echo "                     " (fmt@italics "(To remove this message,\n                      write your own prelude)\n");
        echo "                     " (fmt@href "https://github.com/adam-mcdaniel/dune" "Thank You❤️");

        echo "                     └───────────────────────────┘
                     ╱
                    ╱

          _,____ c--.
        /`  \\   ` _^_\\
    `~~~\\  _/---'\\\\  ^
         `~~~     ~~
    ─────────────────────
"
};

let CATS = ["
     _
   |\\'/-..--.
  / _ _   ,  ;
 `~=`Y'~_<._./
  <`-....__.'",
"

 |\\__/,|   (`\\
 |_ _  |.--.) )
 ( T   )     /
(((^_(((/(((_/",
"

    \\    /\\
     )  ( ')
    (  /  )
     \\(__)|",
"

      ^~^  ,
     ('Y') )
     /   \\/
    (\\|||/)",
"   .       .
   \\`-\"'\"-'/
    } 6 6 {
   =.  Y  ,=
     /^^^\\  .
    /     \\  )
   (  )-(  )/
    \"\"   \"\"",
"

         /\\_/\\
    ____/ o o \\
  /~____  =Y= /
 (______)__m_m)"
];

let prompt = cwd -> fmt@bold ((fmt@dark@blue "(dune) ") + (fmt@bold (fmt@dark@green cwd)) + (fmt@bold (fmt@dark@blue "$ ")));
let incomplete_prompt = cwd -> ((len cwd) + (len "(dune) ")) * " " + (fmt@bold (fmt@dark@yellow "> "));

let shrew = _ ~> {
"
          _,____ c--.
        /`  \\   ` _^_\\
    `~~~\\  _/---'\\\\  ^
         `~~~     ~~
    ─────────────────────
"
};

let turnedshrew = _ ~> {
"
      .--p_____,_
     /_^_ `   /  `\\
     ^  //'---\\_  /~~~
       ~~     ~~~`
     ──────────────────
"
};

let shrewsay = text -> {
    let title = "Wild Dune Shrew";


    let cols = 22;
    let text = fmt@wrap text cols;
    let text-lines = lines text;
    if (len text-lines) == 1 {
        if (len text) < cols {
            let cols = len text;
        }
    }
    let rows = len text-lines;
    let spacing = 25;

    for line in (lines (widget@create title text cols + 2 rows + 2)) {
        echo " " * spacing line;
    }

    for i in 0 to 2 {
        echo " " * (spacing - i) "╱";
    }

    echo (shrew ());
};

let turnedshrewsay = text -> {
    let title = "Wild Dune Shrew";

    let cols = 27;
    let text = fmt@wrap text cols;
    let text-lines = lines text;
    if (len text-lines) == 1 {
        if (len text) < cols {
            let cols = len text;
        }
    }
    let rows = len text-lines;
    let spacing = 20;

    for line in (lines (widget@create title text cols + 2 rows + 2)) {
        echo " " * spacing line;
    }

    for i in 0 to 2 {
        echo " " * (spacing - i) "╱";
    }

    echo (turnedshrew ());
};

let about = _ ~> {
    echo (
    widget@joiny
        (widget@create "About"
"          Hello, welcome to " + (fmt@yellow "Dune Shell!") + "
      Written by: http://adam-mcdaniel.net\n\nI wrote Dune to be a nice environment for devs while they work! It's a very cozy shell with high customizability, so you can make it how you'd like." 50 10)

            (widget@joinx
            (widget@create "Features"
"Dune has a wide set of
features, it's basically a
full blown language!

It supports several uncommon
features in a shell, such as:
operator overloading,
lambdas, macros, quoted
expressions like Lisp, and
more!

Dune's libraries are very
extensive. There are
libraries for:

☞ A simple widget system🪟
☞ OS information        💽
☞ Randomness            🔀
☞ Basic math, trig, etc.🧮
☞ File system operations📂
☞ Text color and styling📝
☞ Functional programming🔗
☞ Date and time         🕒

And more!"
    30 28)

            (widget@joiny
                (widget@create "About the Author" "I'm a sophomore at\nthe University of\nTennessee🏴󠁵󠁳󠁴󠁮󠁿\nstudying Computer💻\nScience🧪.\n\nI'm extremely \ninterested in\nlanguage design\n& compiler design.\nCheck out my other\nprojects on GitHub:\n\nadam-mcdaniel" 20 18)
                (widget@create "Cat" (rand@choose CATS) 20 10)
    )))
};


let welcomebanner = _ ~> {


    let logo = "
        ██████╗ ██╗   ██╗███╗   ██╗███████╗
        ██╔══██╗██║   ██║████╗  ██║██╔════╝
        ██║  ██║██║   ██║██╔██╗ ██║█████╗
        ██║  ██║██║   ██║██║╚██╗██║██╔══╝
        ██████╔╝╚██████╔╝██║ ╚████║███████╗
        ╚═════╝  ╚═════╝ ╚═╝  ╚═══╝╚══════╝
                                     ";

    let logo = "

        ██████╗░██╗░░░██╗███╗░░██╗███████╗
        ██╔══██╗██║░░░██║████╗░██║██╔════╝
        ██║░░██║██║░░░██║██╔██╗██║█████╗░░
        ██║░░██║██║░░░██║██║╚████║██╔══╝░░
        ██████╔╝╚██████╔╝██║░╚███║███████╗
        ╚═════╝░░╚═════╝░╚═╝░░╚══╝╚══════╝
";

    (_ -> {
        let now = time@now ();
        let time-emoji = if now@hour <= 6 "🌃"
            else if now@hour <= 10 "🌅"
            else if now@hour <= 18 "🌤️ "
            else "🌃";
        let date-emoji = if now@month == 1 "⛄"
            else if now@month == 2 "💖"
            else if now@month == 3 "🍀"
            else if now@month == 4 "🌂"
            else if now@month == 5 "🌻"
            else if now@month == 6 "🌞"
            else if now@month == 7 "🌊"
            else if now@month == 8 "📝"
            else if now@month == 9 "🍎"
            else if now@month == 10 "🎃"
            else if now@month == 11 "🍂"
            else if now@month == 12 "🌨️"
            else "📅";
        let zodiac-emoji = if now@month == 1 (if now@day < 20 "🐐" else "🏺")
            else if now@month == 2 (if now@day < 19 "🏺" else "🐟")
            else if now@month == 3 (if now@day < 21 "🐟" else "🐏")
            else if now@month == 4 (if now@day < 20 "🐏" else "🐂")
            else if now@month == 5 (if now@day < 21 "🐂" else "👬")
            else if now@month == 6 (if now@day < 21 "👬" else "🦀")
            else if now@month == 7 (if now@day < 23 "🦀" else "🦁")
            else if now@month == 8 (if now@day < 23 "🦁" else "👩")
            else if now@month == 9 (if now@day < 23 "👩" else "⚖️")
            else if now@month == 10 (if now@day < 23 "⚖️" else "🦂")
            else if now@month == 11 (if now@day < 22 "🦂" else "🏹")
            else if now@month == 12 (if now@day < 22 "🏹" else "🐐")
            else "⭐";
        echo "┌─────────────────Welcome to ...─────────────────┐";
        for ch in (chars logo) {
            print (fmt@bold (if ch == "█" {
               fmt@faint (fmt@red ch)
            } else {
               fmt@faint (fmt@dark@blue ch)
            }));
        }
        echo "";
        echo "        The time is " + (fmt@magenta now@time@str) + " " + time-emoji + " on " + (fmt@cyan now@date@str);
        echo "└────────────────────────────────────────────────┘";
    }) ();

};


let is-leapyear = year -> {
    if year % 4 == 0 && year % 100 != 0 {
        True
    } else if year % 100 == 0 && year % 400 == 0 {
        True
    } else {
        False
    }
};

let days-in-month = month -> year -> {
    if month == 2 {
        28 + (if (is-leapyear year) 1 else 0)
    } else {
        31 - (((month - 1) % 7) % 2)
    }
};

let day-of-week = m -> d -> y -> {
    let t = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4];

    if m < 3 {
        let y = y - 1
    }

    (((y + (int(y // 4.0))) - (int(y // 100.0))) + (int(y // 400.0)) + t@(m - 1) + d) % 7
};

let WEEKDAYS = [
	"Sunday",
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
	"Saturday"
];

let MONTHS = [
	"January",
	"February",
	"March",
	"April",
	"May",
	"June",
	"July",
	"August",
	"September",
	"October",
	"November",
	"December"
];

let make-calendar = m -> d -> y -> {
    let now = {month=m, day=d, year=y};
    let result = MONTHS@(now@month - 1) + " " + (str now@day) + ", " + (str now@year) + "\n";
	let result = " " * ((28 - (len result)) // 2 + 1) + result;
    let result = result + " Su  Mo  Tu  We  Th  Fr  Sa\n";

    let dof = day-of-week now@month 1 now@year;
    let dim = days-in-month now@month now@year;

    for i in 0 to dof {
        let result = result + "    ";
    }

    for i in 1 to dim + 1 {
        let num = str i;
        if (len num) < 2 {
            let num = (if now@day == i " *" else "  ") + num
        } else {
            let num = (if now@day == i "*" else " ") + num
        }

        let result = result + num + (if (i + dof) % 7 == 0 "\n" else " ")
    }
    widget@create "Calendar" result 30 10
};

let cal = _ ~> {
    (_ -> {
        let now = time@now ();
        make-calendar now@month now@day now@year
    }) ();
};



let welcome = _ ~> {
    welcomebanner ();
    (_ -> {
        let now = time@now ();
        echo (widget@joinx
            (make-calendar now@month now@day now@year)
            (widget@create "Cat" (rand@choose CATS) 20 10));
    }) ();
};


let yesorno = _ -> {
    (input (fmt@blue "(y/n) ")) != "n"
};

let wait = _ -> {
   input (fmt@italics (fmt@blue "(Press enter to continue) "));
};


let intro = _ ~> {
    clear ();
    welcomebanner ();

    shrewsay "Hey there! Is this your first time using Dune?";
    if (yesorno ()) {
        clear ();
        welcomebanner ();
        shrewsay "Then let's get started!";
        wait ();

        clear ();
        welcomebanner ();
        about ();
        turnedshrewsay "First off, here's some background information about Dune!";
        wait ();

        clear ();
        welcomebanner ();
        shrewsay "To execute a program in Dune, simply call the program the same way you would in bash or Powershell!\n\n\n$ prog arg1 arg2 ...";
        wait ();

        clear ();
        welcomebanner ();
        turnedshrewsay "You can also define macros for Dune, and call them the same way you would a program! (Macros called without arguments are implicitly passed the current working directory as an argument)\n\n\n$ cd ..";
        wait ();

        clear ();
        welcomebanner ();
        shrewsay "To define variables (which also act as environment variables), simply use the `let` keyword!\n\n\n$ let x = 5";
        wait ();

        clear ();
        welcomebanner ();
        turnedshrewsay "That should be enough to get you started! If you have any questions, just call the `help` macro! To ask for general help, run `help me`!\n\n\n$ help me";
        wait ();

        clear ();
        welcomebanner ();
        turnedshrewsay "Good luck! I really hope you enjoy my shell! 😄❤️";
        wait ();

    } else {
        clear ();
        welcomebanner ();
        turnedshrewsay "Oh good! I'll assume you know your way around. To write your own startup script, instead of this default script, write a `.dune-prelude` file in your home directory! Bye!";
        wait ();
    }

    clear ();
    welcome ();
};

let old-report = report;
let REPORT_COUNT = 0;
let report = val ~> {
    old-report val;
    if REPORT_COUNT == 50 {
        donate ();
    }
    let REPORT_COUNT = REPORT_COUNT + 1;
};

let old-help = help;
let help = val ~> {
    if val == CWD || val == 'me {
        old-help me;
        echo "\n";
        donate ();
    } else if val == 'builtin {
        old-help builtin;
    } else if val == 'lib {
        old-help lib;
    } else if val == 'syntax {
        old-help syntax;
    } else if val == 'types {
        old-help types;
    } else if val == 'scripting {
        old-help scripting;
    } else if val == 'prelude {
        old-help prelude;
    } else {
        old-help val;
    }
};

intro ();
