import requests
import pandas as pd
from providers.base_provider import BaseProvider
from config.settings import POLYGON_API_KEY

class PolygonProvider(BaseProvider):
		def fetch_data(self, symbol, interval="DAILY", api_key=POLYGON_API_KEY, asset_type="forex"):
				if asset_type == "forex":
						return self._fetch_forex_data(symbol, interval, api_key)
				elif asset_type == "stock":
						return self.fetch_stock_data(symbol, interval, api_key)
				else:
						raise ValueError(f"Unsupported asset type: {asset_type}")
				
		def _fetch_forex_data(self, symbol, interval="DAILY", api_key=POLYGON_API_KEY):
				"""
				Fetch forex data from Polygon.io.
				:param symbol: Forex pair (e.g., "USDJPY")
				:param interval: Time interval (e.g., "DAILY", "MINUTE")
				:param api_key: API key for Polygon.io
				:return: Pandas DataFrame with OHLCV data
				"""
				# Construct the API URL
				if interval == "DAILY":
						url = f"https://api.polygon.io/v2/aggs/ticker/C:{symbol}/range/1/day/2000-01-01/2023-12-31?adjusted=true&sort=asc&limit=50000&apiKey={api_key}"
				elif interval == "MINUTE":
						url = f"https://api.polygon.io/v2/aggs/ticker/C:{symbol}/range/1/minute/2000-01-01/2023-12-31?adjusted=true&sort=asc&limit=50000&apiKey={api_key}"
				else:
						raise ValueError(f"Unsupported interval: {interval}")

				# Fetch data
				response = requests.get(url)
				data = response.json()

				if "error" in data:
						error_msg = data.get("error", "Unknown error")
						raise Exception(f"Error fetching data: {error_msg}")

				if "results" not in data or not data["results"]:
						raise Exception("No data available for the given symbol and interval.")

				# Parse results into a DataFrame
				df = pd.DataFrame(data["results"])
				df.rename(columns={
						"o": "Open",
						"h": "High",
						"l": "Low",
						"c": "Close",
						"v": "Volume",
						"t": "Timestamp"
				}, inplace=True)

				# Convert timestamp to datetime
				df["Timestamp"] = pd.to_datetime(df["Timestamp"], unit="ms")
				df.set_index("Timestamp", inplace=True)

				# Ensure numeric types
				df[["Open", "High", "Low", "Close", "Volume"]] = df[["Open", "High", "Low", "Close", "Volume"]].astype(float)

				# Log the fetched data
				print(f"Fetched {len(df)} rows of data for {symbol}.")
				if df.empty:
						raise Exception("Fetched data is empty. Please check the symbol and interval.")

				return df.sort_index()
		
		def fetch_stock_data(self, symbol, interval="DAILY", api_key=POLYGON_API_KEY):
				url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/range/1/day/2000-01-01/2023-12-31?adjusted=true&sort=asc&limit=50000&apiKey={api_key}"
				response = requests.get(url)
				data = response.json()
				
				if "error" in data:
						error_msg = data.get("error", "Unknown error")
						raise Exception(f"Error fetching stock data: {error_msg}")

				if "results" not in data or not data["results"]:
						raise Exception("No stock data available for the given symbol and interval.")

				df = pd.DataFrame(data["results"])
				df.rename(columns={
						"o": "Open",
						"h": "High",
						"l": "Low",
						"c": "Close",
						"v": "Volume",
						"t": "Timestamp"
				}, inplace=True)

				df["Timestamp"] = pd.to_datetime(df["Timestamp"], unit="ms")
				df.set_index("Timestamp", inplace=True)
				df[["Open", "High", "Low", "Close", "Volume"]] = df[["Open", "High", "Low", "Close", "Volume"]].astype(float)
				return df.sort_index()

		def fetch_news(self, symbol, api_key=POLYGON_API_KEY):
				url = f"https://api.polygon.io/v2/reference/news?ticker={symbol}&apiKey={api_key}"
				response = requests.get(url)
				data = response.json()

				if "error" in data:
						error_msg = data.get("error", "Unknown error")
						raise Exception(f"Error fetching news: {error_msg}")

				return data.get("results", [])

		def fetch_dividends(self, symbol, api_key=POLYGON_API_KEY):
					url = f"https://api.polygon.io/v2/reference/dividends/{symbol}?apiKey={api_key}"
					response = requests.get(url)
					data = response.json()
					
					if "error" in data:
							error_msg = data.get("error", "Unknown error")
							raise Exception(f"Error fetching dividends: {error_msg}")

					dividends = data["results"]

					# Sort dividends by ex-dividend date (most recent first)
					dividends.sort(key=lambda x: x['exDate'], reverse=True)

					# Return only the latest 5 dividends
					return dividends[:5]

		def fetch_options(self, symbol, expiration_date=None, api_key=POLYGON_API_KEY):
				if expiration_date:
						url = f"https://api.polygon.io/v2/snapshot/options/{symbol}/{expiration_date}?apiKey={api_key}"
				else:
						url = f"https://api.polygon.io/v2/snapshot/options/{symbol}?apiKey={api_key}"

				response = requests.get(url)
				data = response.json()
				
				if "error" in data:
						error_msg = data.get("error", "Unknown error")
						raise Exception(f"Error fetching options: {error_msg}")

				return data.get("results", [])
		
		def fetch_earnings(self, symbol, api_key=POLYGON_API_KEY):
				url = f"https://api.polygon.io/v2/reference/earnings/{symbol}?apiKey={api_key}"
				response = requests.get(url)
				
				# Check for HTTP errors
				if response.status_code != 200:
						raise Exception(f"HTTP Error: {response.status_code} - {response.reason}")

				# Print the raw response for debugging
				print("Raw API Response:", response.text)

				try:
						data = response.json()
				except ValueError as e:
						raise Exception(f"Error parsing JSON: {str(e)}")

				# Handle API-specific errors
				if "error" in data:
						raise Exception(f"API Error: {data['error']}")
				if "results" not in data:
						raise Exception("Unexpected API response format.")

				return data["results"]

		def fetch_sector_performance(self, api_key=POLYGON_API_KEY):
				url = f"https://api.polygon.io/v2/snapshot/locale/us/markets/stocks/sectors?apiKey={api_key}"
				response = requests.get(url)
				data = response.json()

				if "error" in data:
						error_msg = data.get("error", "Unknown error")
						raise Exception(f"Error fetching sector performance: {error_msg}")

				return data.get("results", {})
		
		def fetch_latest_price(self, symbol, api_key=POLYGON_API_KEY):
				url = f"https://api.polygon.io/v2/snapshot/locale/us/markets/stocks/tickers/{symbol}?apiKey={api_key}"
				response = requests.get(url)
				data = response.json()
				print(data)
				if "error" in data:
						error_msg = data.get("error", "Unknown error")
						raise Exception(f"Error fetching latest price: {error_msg}")

				latest_price = data["ticker"]["lastQuote"]["P"]
				return float(latest_price)
		
		def fetch_aggregate_data(self, api_key=POLYGON_API_KEY):
				url = f"https://api.polygon.io/v2/aggs/grouped/locale/us/market/stocks/2023-10-25?adjusted=true&apiKey={api_key}"
				response = requests.get(url)
				data = response.json()

				if "error" in data:
						error_msg = data.get("error", "Unknown error")
						raise Exception(f"Error fetching aggregate data: {error_msg}")

				results = data.get("results", [])
				df = pd.DataFrame(results)
				df.rename(columns={
						"o": "Open",
						"h": "High",
						"l": "Low",
						"c": "Close",
						"v": "Volume",
						"t": "Timestamp"
				}, inplace=True)

				df["Timestamp"] = pd.to_datetime(df["Timestamp"], unit="ms")
				df.set_index("Timestamp", inplace=True)
				df[["Open", "High", "Low", "Close", "Volume"]] = df[["Open", "High", "Low", "Close", "Volume"]].astype(float)
				return df.sort_index()