# Load required libraries
library(httr)
library(highcharter)
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
## Highcharts (www.highcharts.com) is a Highsoft software product which is
## not free for commercial and Governmental use
library(quantmod)
## Loading required package: xts
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## Loading required package: TTR
library(scales)
library(DT)

# Set highcharter options
hcoptslang <- getOption("highcharter.lang")
hcoptslang$thousandsSep <- ","
options(highcharter.lang = hcoptslang)

# ********************************************************************************************
# Function: Get Financials (Income Statement, Cash Flow, Balance Sheet)
# ********************************************************************************************
getFins <- function(symbol, AQ, FS){
  URL <- paste0('https://finviz.com/api/statement.ashx?t=', symbol, '&so=F&s=', FS, AQ)
  
  headers <- c(
    'Host' = 'finviz.com',
    'User-Agent' = 'Mozilla/5.0',
    'Accept' = '*/*',
    'Referer' = paste0('https://finviz.com/quote.ashx?t=', symbol),
    'Connection' = 'keep-alive'
  )

  response <- httr::GET(url = URL, add_headers(headers))
  content_data <- httr::content(response)

  if (is.null(content_data$data)) stop("No financial data found for ", symbol)

  tbl <- unlist(content_data$data)
  if (length(tbl) == 0) stop("Financial data is empty for ", symbol)

  row_names <- gsub("1", "", unique(names(tbl)[seq(1, length(tbl), 8)]))
  df <- matrix(tbl, ncol = 8, byrow = TRUE)
  df <- data.frame(df, row.names = row_names)

  colnames(df) <- df[1,]
  df <- df[-1,]

  df_numeric <- data.frame(apply(df, 2, function(x) as.numeric(gsub(",", "", x))), row.names = rownames(df))
  colnames(df_numeric) <- colnames(df)

  df_numeric <- df_numeric[rowSums(is.na(df_numeric)) != ncol(df_numeric), ]
  return(df_numeric)
}

# ********************************************************************************************
# Function: Plot Financial Trends
# ********************************************************************************************
plotTrends <- function(ticker, metric, data_source) {
  data_selected <- subset(data_source, row.names(data_source) == metric)

  if (nrow(data_selected) == 0) stop("No data found for ", metric)

  data_selected <- rev(data_selected)
  data_selected <- as.data.frame(t(data_selected))
  data_selected$date <- row.names(data_selected)

  data_selected <- data.frame(
    date = format(as.Date(data_selected$date, "%m/%d/%Y"), "%b %d '%y"),
    value = data_selected[,1]
  )
  
  data_selected$pct_change <- c(NA, diff(data_selected$value) / head(data_selected$value, -1))
  data_selected$yoy_change <- c(rep(NA, 4), diff(data_selected$value, lag = 4) / head(data_selected$value, -4))

  data_selected %>% 
    hchart('column', hcaes(x = 'date', y = 'value'), name = "Value") %>%
    hc_title(text = paste0(ticker, ": ", metric), align = "center") %>%
    hc_yAxis_multiples(
      list(title = list(text = "Value"), opposite = FALSE),
      list(showLastLabel = FALSE, opposite = TRUE, title = list(text = "% Change"), min = -100, max = 100)
    ) %>%
    hc_add_series(round(data_selected$yoy_change * 100, 2), yAxis = 1, name = "YoY % Change") %>%
    hc_add_series(round(data_selected$pct_change * 100, 2), yAxis = 1, name = "QoQ % Change")
}

# ********************************************************************************************
# Function: Convert Balance Sheet to Percentages
# ********************************************************************************************
pctBS <- function(BS) {
  rownames(BS)[is.na(rownames(BS))] <- paste0("Row_", seq_len(sum(is.na(rownames(BS)))))
  BS <- BS[rowSums(is.na(BS)) != ncol(BS), ]

  asset_index <- which(rownames(BS) == "Total Assets")      
  liability_index <- which(rownames(BS) == "Total Liabilities") 
  equity_index <- which(rownames(BS) == "Total Equity") 

  if (length(asset_index) == 0 | length(liability_index) == 0 | length(equity_index) == 0) {
    stop("Missing key financial values (Assets, Liabilities, Equity).")
  }

  BS_numeric <- data.frame(lapply(BS, function(x) as.numeric(gsub(",", "", x))), row.names = rownames(BS))

  asset_divisor <- as.numeric(BS_numeric[asset_index, ])
  liability_divisor <- as.numeric(BS_numeric[liability_index, ])
  equity_divisor <- as.numeric(BS_numeric[equity_index, ])

  asset_divisor[asset_divisor == 0] <- NA
  liability_divisor[liability_divisor == 0] <- NA
  equity_divisor[equity_divisor == 0] <- NA

  total_assets <- sweep(BS_numeric[1:asset_index, ], 2, asset_divisor, "/")
  total_liabilities <- sweep(BS_numeric[(asset_index+1):liability_index, ], 2, liability_divisor, "/")
  total_equity <- sweep(BS_numeric[(liability_index+1):equity_index, ], 2, equity_divisor, "/")

  total_assets <- apply(total_assets, 2, scales::percent, accuracy = 0.01, na.rm = TRUE)
  total_liabilities <- apply(total_liabilities, 2, scales::percent, accuracy = 0.01, na.rm = TRUE)
  total_equity <- apply(total_equity, 2, scales::percent, accuracy = 0.01, na.rm = TRUE)

  BS_pct <- rbind(data.frame(total_assets), data.frame(total_liabilities), data.frame(total_equity))
  rownames(BS_pct) <- c(rownames(BS)[1:asset_index], rownames(BS)[(asset_index+1):liability_index], rownames(BS)[(liability_index+1):equity_index])

  return(BS_pct)
}

# ********************************************************************************************
# Execution: Get AAPL Financials & Plot Trends
# ********************************************************************************************

ticker <- "AAPL"

# Fetch Financial Statements
AAPL_IS <- getFins(ticker, "A", "I")  # Income Statement (Annual)
## Warning in FUN(newX[, i], ...): NAs introduced by coercion
## Warning in FUN(newX[, i], ...): NAs introduced by coercion
## Warning in FUN(newX[, i], ...): NAs introduced by coercion
## Warning in FUN(newX[, i], ...): NAs introduced by coercion
## Warning in FUN(newX[, i], ...): NAs introduced by coercion
## Warning in FUN(newX[, i], ...): NAs introduced by coercion
## Warning in FUN(newX[, i], ...): NAs introduced by coercion
## Warning in FUN(newX[, i], ...): NAs introduced by coercion
AAPL_BS <- getFins(ticker, "A", "B")  # Balance Sheet (Annual)

# Plot Key Financial Trends
plotTrends(ticker, "Total Revenue", AAPL_IS)
plotTrends(ticker, "Net Income", AAPL_IS)
plotTrends(ticker, "Total Liabilities", AAPL_BS)
# Convert Balance Sheet to Percentages
AAPL_BS_pct <- pctBS(AAPL_BS)

# Display Data Table
datatable(AAPL_BS_pct, options = list(pageLength = 10, autoWidth = TRUE))