import os, json, asyncio
from datetime import datetime
from lxml import etree
from playwright.async_api import async_playwright

# Config
API_URL = "https://www.nseindia.com/api/corporates-financial-results?index=equities&symbol=AAKASH&period=Quarterly"
TO_DATE_THRESHOLD = datetime.strptime("31-Dec-2024", "%d-%b-%Y")
OUTPUT_DIR = './json/'
os.makedirs(OUTPUT_DIR, exist_ok=True)

# Pre-generated quarter code mapping from 30-Sep-2022 (code=115)
quarter_code_map = {
    "30-Sep-2022": 115, "31-Dec-2022": 116, "31-Mar-2023": 117, "30-Jun-2023": 118,
    "30-Sep-2023": 119, "31-Dec-2023": 120, "31-Mar-2024": 121, "30-Jun-2024": 122,
    "30-Sep-2024": 123, "31-Dec-2024": 124, "31-Mar-2025": 125
}

def get_first(result):
    return result[0].text.strip() if result and result[0].text else None

def parse_nse_date(raw_date):
    for fmt in ("%d-%b-%Y", "%Y-%m-%d"):
        try:
            return datetime.strptime(raw_date, fmt).strftime("%d-%b-%y")
        except:
            continue
    raise ValueError(f"Unrecognized date format: {raw_date}")

def extract_data(xml_bytes):
    root = etree.fromstring(xml_bytes)
    ns = {'in-bse-fin': "http://www.bseindia.com/xbrl/fin/2020-03-31/in-bse-fin"}
    xp = lambda path: root.xpath(path, namespaces=ns)
    def gstr(path): return get_first(xp(path)) or ""
    def gnum(path):
        val = get_first(xp(path))
        return str(round(float(val.replace(',', '')) / 1_000_000, 2)) if val else "0"

    data = {
        'symbol': gstr("//in-bse-fin:Symbol[@contextRef='OneD']"),
        'company_name': gstr("//in-bse-fin:NameOfTheCompany[@contextRef='OneD']"),
        'Net Sales': gnum("//in-bse-fin:RevenueFromOperations[@contextRef='OneD']"),
        'Other Income': gnum("//in-bse-fin:OtherIncome[@contextRef='OneD']"),
        'Total Income': gnum("//in-bse-fin:Income[@contextRef='OneD']"),
        'Expenditure': gnum("//in-bse-fin:Expenses[@contextRef='OneD']"),
        'Cost of Materials Consumed': gnum("//in-bse-fin:CostOfMaterialsConsumed[@contextRef='OneD']"),
        'Finance Costs': gnum("//in-bse-fin:FinanceCosts[@contextRef='OneD']"),
        'Changes in inventories of finished goods, work-in-progress and stock-in-trade': gnum("//in-bse-fin:ChangesInInventoriesOfFinishedGoodsWorkInProgressAndStockInTrade[@contextRef='OneD']"),
        'Purchases of stock-in-trade': gnum("//in-bse-fin:PurchasesOfStockInTrade[@contextRef='OneD']"),
        'Employee benefit expense': gnum("//in-bse-fin:EmployeeBenefitExpense[@contextRef='OneD']"),
        'Depreciation and amortisation expense': gnum("//in-bse-fin:DepreciationDepletionAndAmortisationExpense[@contextRef='OneD']"),
        'Profit after Interest but before Exceptional Items': gnum("//in-bse-fin:ProfitBeforeExceptionalItemsAndTax[@contextRef='OneD']"),
        'Exceptional Item': gnum("//in-bse-fin:ExceptionalItemsBeforeTax[@contextRef='OneD']"),
        'Profit (+)/ Loss (-) from Ordinary Activities before Tax': gnum("//in-bse-fin:ProfitBeforeTax[@contextRef='OneD']"),
        'Tax': gnum("//in-bse-fin:TaxExpense[@contextRef='OneD']"),
        'Net Profit (+)/ Loss (-) from Ordinary Activities after Tax': gnum("//in-bse-fin:ProfitLossForPeriodFromContinuingOperations[@contextRef='OneD']"),
        'Net Profit': gnum("//in-bse-fin:ProfitLossForPeriod[@contextRef='OneD']"),
        'Current tax': gnum("//in-bse-fin:CurrentTax[@contextRef='OneD']"),
        'Deferred tax': gnum("//in-bse-fin:DeferredTax[@contextRef='OneD']"),
        'Other Comprehensive Income Net of Taxes': gnum("//in-bse-fin:OtherComprehensiveIncomeNetOfTaxes[@contextRef='OneD']"),
        'Total Comprehensive Income for the Period': gnum("//in-bse-fin:ComprehensiveIncomeForThePeriod[@contextRef='OneD']"),
        'Share of profit(loss) of associates and joint ventures': gnum("//in-bse-fin:ShareOfProfitLossOfAssociatesAndJointVenturesAccountedForUsingEquityMethod[@contextRef='OneD']"),
        'Basic EPS for continuing operation': gstr("//in-bse-fin:BasicEarningsLossPerShareFromContinuingOperations[@contextRef='OneD']"),
        'Diluted EPS for continuing operation': gstr("//in-bse-fin:DilutedEarningsLossPerShareFromContinuingOperations[@contextRef='OneD']"),
        'Basic for discontinued & continuing operation': gstr("//in-bse-fin:BasicEarningsLossPerShareFromContinuingAndDiscontinuedOperations[@contextRef='OneD']"),
        'Diluted for discontinued & continuing operation': gstr("//in-bse-fin:DilutedEarningsLossPerShareFromContinuingAndDiscontinuedOperations[@contextRef='OneD']"),
        'Data Type': gstr("//in-bse-fin:NatureOfReportStandaloneConsolidated[@contextRef='OneD']")
    }

    for i in range(1, 50):
        ctx = f"OneOperatingExpenses0{i}D"
        desc = gstr(f"//in-bse-fin:DescriptionOfOtherExpenses[@contextRef='{ctx}']")
        if desc.lower() in ["other expenses", "other expense", "others"]:
            data["Other Expenses"] = gnum(f"//in-bse-fin:OtherExpenses[@contextRef='{ctx}']")
            break
    else:
        data["Other Expenses"] = gnum("//in-bse-fin:OtherExpenses[@contextRef='OneD']")
    return data

async def fetch_symbol_quarters():
    async with async_playwright() as p:
        browser = await p.firefox.launch(headless=True)
        context = await browser.new_context()
        page = await context.new_page()

        print("🌐 Visiting NSE homepage...")
        await page.goto("https://www.nseindia.com", timeout=60000)
        await page.wait_for_timeout(3000)

        print("📦 Fetching Financial Results for symbol...")
        response = await context.request.get(API_URL, headers={
            "Accept": "application/json",
            "Referer": "https://www.nseindia.com/"
        })
        json_data = await response.json()
        print(f"✅ Total docs: {len(json_data)}")

        for item in json_data:
            to_date_str = item.get("toDate", "")
            to_date = datetime.strptime(to_date_str, "%d-%b-%Y")
            if to_date < TO_DATE_THRESHOLD:
                continue

            qtr_code = quarter_code_map.get(to_date_str)
            if not qtr_code:
                print(f"⚠️ Skipping unknown quarter: {to_date_str}")
                continue

            xbrl_url = item["xbrl"].split("<br>")[0]
            print(f"➡️ Fetching XBRL for {item['symbol']} | {to_date_str}")

            try:
                res = await page.goto(xbrl_url, timeout=60000)
                if not res or not res.ok:
                    print(f"❌ Failed to fetch XML: {xbrl_url}")
                    continue
                xml = await res.text()
                xml_bytes = xml.encode("utf-8")
                data = extract_data(xml_bytes)

                data.update({
                    "isin_number": item["isin"],
                    "Type": item["audited"],
                    "Date Begin": parse_nse_date(item["fromDate"]),
                    "Date End": parse_nse_date(item["toDate"]),
                    "Description": "Amount (Rs. million)",
                    "qtr_code": qtr_code,
                    "image_id": item.get("image_id"),
                    "image_url": item.get("image_url", ""),
                    "BSE/NSE": "NSE"
                })

                filename = os.path.join(OUTPUT_DIR, f"{item['symbol']}_{to_date_str.replace('-', '')}_{data['Data Type']}.json")
                with open(filename, "w") as f:
                    json.dump(data, f, indent=2)
                print(f"✅ Saved {filename}")

            except Exception as e:
                print(f"❌ Error for {item['symbol']}: {e}")
                continue

        await browser.close()
        print("🏁 Done.")

if __name__ == "__main__":
    asyncio.run(fetch_symbol_quarters())
