from __future__ import annotations
import re
import pandas as pd
from pathlib import Path
from .base import BaseParser, StatementMeta, extract_text, amount, norm, finalize, page_of_line
from .common import DATE_TOKEN_PATTERN, find, date_iso

class IDFCFirstParser(BaseParser):
    bank_name='IDFC FIRST Bank'; parser_name='IDFCFirstParser'
    @classmethod
    def detect(cls,text):
        u=text.upper(); return 0.99 if 'IDFC FIRST BANK' in u and 'STATEMENT PERIOD' in u else 0
    def parse(self,path,text=None):
        text=text or extract_text(path)
        meta=StatementMeta(bank_name=self.bank_name,source_file=Path(path).name,parser_name=self.parser_name,confidence='High')
        meta.customer_name=find(r'CUSTOMER NAME\s*:\s*([^\n]+)',text)
        meta.account_number=find(r'ACCOUNT NO\s*:\s*([0-9X*]+)',text)
        meta.customer_id=find(r'CUSTOMER ID\s*:\s*([0-9X*]+)',text)
        meta.ifsc=find(r'IFSC\s*:\s*([A-Z0-9]+)',text)
        m=re.search(rf'STATEMENT PERIOD\s*:\s*({DATE_TOKEN_PATTERN})\s+TO\s+({DATE_TOKEN_PATTERN})', text, re.I)
        if m: meta.period_from=date_iso(m.group(1)); meta.period_to=date_iso(m.group(2))
        m=re.search(r'Opening Balance\s+Total Debit\s+Total Credit\s+Closing Balance\s*\n\s*([\d,.]+)\s+([\d,.]+)\s+([\d,.]+)\s+([\d,.]+)',text,re.I)
        if m: meta.opening_balance,meta.total_debit,meta.total_credit,meta.closing_balance=map(amount,m.groups())
        lines=text.splitlines(); rows=[]; current=None; pos=0
        pat=re.compile(rf'^\s*({DATE_TOKEN_PATTERN})\s+({DATE_TOKEN_PATTERN})\s+(.*)$', re.I)
        for line in lines:
            mm=pat.match(line)
            if mm:
                if current: rows.append(current)
                current={'transaction_date':mm.group(1),'value_date':mm.group(2),'body':mm.group(3),'source_page':page_of_line(text,pos)}
            elif current and line.strip() and not re.match(r'^(STATEMENT|Opening Balance|REGISTERED OFFICE|Page \d+)',line.strip(),re.I):
                current['body']+=' '+line.strip()
            pos+=len(line)+1
        if current: rows.append(current)
        out=[]; prev=meta.opening_balance
        for r in rows:
            body=norm(r['body']); nums=list(re.finditer(r'(?<!\d)(?:\d{1,3}(?:,\d{2,3})+|\d+)\.\d{2}(?!\d)',body))
            if not nums: continue
            bal=amount(nums[-1].group()); rem=body[:nums[-1].start()].strip(); vals=[amount(x.group()) for x in nums[:-1]]
            debit=credit=None
            if vals:
                txn=vals[-1]
                if prev is not None and bal is not None:
                    d1=round(prev-txn,2); c1=round(prev+txn,2)
                    if abs(d1-bal)<0.02: debit=txn
                    elif abs(c1-bal)<0.02: credit=txn
                    else:
                        # explicit columns often leave one amount only; infer from change
                        credit=txn if bal>=prev else None; debit=txn if bal<prev else None
                else: credit=txn
            ref=''
            z=re.search(r'(?:UPI|NEFT|IMPS|RTGS)[/-](?:MOB/|OPM/|INET/|DR/|CR/)?([A-Z0-9]{8,})',rem,re.I)
            if z: ref=z.group(1)
            out.append({**r,'narration':rem,'reference_no':ref,'debit':debit,'credit':credit,'balance':bal})
            if bal is not None: prev=bal
        return meta,finalize(pd.DataFrame(out),meta)
