#!/usr/bin/env python3
"""Generate Amex complaint PDF with letter + screenshot exhibits."""

from fpdf import FPDF
from PIL import Image
import os
import glob

class AmexPDF(FPDF):
    def header(self):
        pass
    
    def footer(self):
        if self.page_no() > 0:
            self.set_y(-15)
            self.set_font('Helvetica', 'I', 8)
            self.cell(0, 10, f'Page {self.page_no()}', align='C')

    def section_title(self, title):
        self.set_font('Helvetica', 'B', 12)
        self.cell(0, 8, title, new_x="LMARGIN", new_y="NEXT")
        self.ln(2)
    
    def body_text(self, text):
        self.set_font('Helvetica', '', 10)
        self.multi_cell(0, 5, text)
        self.ln(2)
    
    def bold_body(self, text):
        self.set_font('Helvetica', 'B', 10)
        self.multi_cell(0, 5, text)
        self.ln(2)
    
    def italic_body(self, text):
        self.set_font('Helvetica', 'I', 10)
        self.multi_cell(0, 5, text)
        self.ln(2)
    
    def timeline_entry(self, date, text):
        self.set_font('Helvetica', 'B', 10)
        self.cell(0, 5, date, new_x="LMARGIN", new_y="NEXT")
        self.set_font('Helvetica', '', 10)
        self.multi_cell(0, 5, text)
        self.ln(3)
    
    def numbered_point(self, num, text):
        self.set_font('Helvetica', 'B', 10)
        self.cell(8, 5, f"{num}.")
        self.set_font('Helvetica', '', 10)
        self.multi_cell(0, 5, text)
        self.ln(2)

pdf = AmexPDF()
pdf.set_auto_page_break(auto=True, margin=20)
pdf.add_page()

# Subject line
pdf.set_font('Helvetica', 'B', 13)
pdf.multi_cell(0, 7, 'Formal Complaint - Request for Dispute Exception\n$1,409.99 Undelivered Product - Member Since 2006')
pdf.ln(8)

# Date
pdf.set_font('Helvetica', '', 10)
pdf.cell(0, 5, 'March 8, 2026', new_x="LMARGIN", new_y="NEXT")
pdf.ln(5)

# Opening
pdf.body_text('Dear American Express Complaints Department,')

pdf.body_text('I have been a loyal American Express business cardholder for 20 years (member since 2006). I am writing regarding my formal complaint and request for an exception to the standard 90-day dispute window for a charge of $1,409.99 for a product that has never been delivered.')

pdf.body_text('I believe the circumstances of this case clearly warrant an exception, as I was acting in good faith throughout, while the merchant has engaged in a documented pattern of billing errors, broken promises, and failure to deliver.')

# Why I Could Not Dispute
pdf.section_title('Why I Could Not Dispute Within 90 Days')
pdf.body_text('I purchased a pre-sale online course on September 2, 2025 for $1,409.99 from Donald Spann (Hybrid Call Center). Because the product was sold as a pre-purchase for a course still in development, and because the merchant repeatedly assured me the course was imminent, I had no basis to dispute the charge during the initial 90-day window. I was waiting in good faith for a product I was explicitly promised would be delivered.')

# Timeline
pdf.section_title('Timeline of Events')

pdf.timeline_entry('August 27-31, 2025:', 'The merchant, Donald Spann, contacted me directly to pitch an online course called "Hybrid Call Center" at a discounted rate of $1,409.99 (described as an "alumni upgrade" from a previous course). He applied sales pressure with a "final reminder" message on August 31.')

pdf.timeline_entry('September 2, 2025:', 'I purchased the course for $1,409.99 via the merchant\'s website (hybridcallcenter.com).')

pdf.timeline_entry('September 8, 2025:', 'The merchant admitted to a major billing error, writing: "We overcharged your card due to the messiest error I\'ve made in my entire career." My American Express card was charged approximately five additional times in varying amounts. The merchant stated the error affected 12 customers.')

pdf.timeline_entry('September 10-12, 2025:', 'The merchant attempted to process refunds for the erroneous charges but encountered issues. He provided screenshots of Stripe refund attempts and stated, "Your card was removed from the account so this doesn\'t happen again." My statement showed $6,811.23 CAD in excess charges across five duplicate transactions from multiple Stripe accounts (see Exhibit B).')

pdf.timeline_entry('September 29, 2025:', 'I followed up regarding outstanding refunds. The merchant responded, "I totally understand... I\'m terribly sorry."')

pdf.timeline_entry('October 2, 2025:', 'The merchant admitted to "having some issues with Stripe" and asked for more time. I expressed concern about carrying over $6,800 CAD in erroneous charges on my card. The merchant promised, "If there\'s any way u end up with that hit I\'ll cover it anyway."')

pdf.timeline_entry('October 14, 2025:', 'With refunds still unprocessed, the merchant himself instructed me to dispute the excess charges with American Express, writing: "Dude still nothing on your end? If not, f--- it, dispute them." I confirmed I had already filed disputes. The duplicate charges were subsequently reversed through American Express. The merchant also admitted to cycling through numerous Stripe payment accounts, stating he was on "probably Stripe number 28."')

pdf.timeline_entry('November 27, 2025:', 'The merchant posted a public video titled "Exciting Updates and Launch Date for the New Course" (see Exhibit C) in which he stated: "I finally have like, 100% go live date for the course. And that go live date is gonna be January 1st." He also acknowledged the extended delay, stating: "It\'s been a hell of a wait. You know, I really apologize." Notably, in this same video, the merchant revealed he was still collecting payments from new customers through informal channels (PayPal and Zelle), stating: "We\'ve been doing it pretty informally, having people send me money on PayPal or Zell."')

pdf.timeline_entry('January 1, 2026:', 'The promised launch date passed. The course was not delivered.')

pdf.timeline_entry('January 22, 2026:', 'I contacted the merchant asking about the course status. He responded that he had been looking for an apartment in Mexico and was "gonna finish recording in it"  -  confirming the course had still not been completed, let alone delivered, nearly five months after my purchase.')

pdf.timeline_entry('February 22, 2026:', 'I formally requested a full refund, explaining that cash flow was tight and I could no longer wait for a product with no delivery date. On February 23, the merchant explicitly agreed, responding: "Hey Mike. Refund is understandable." He then offered to send the refund directly, stating: "Oh I can get it to u direct if u can wait a few days."')

pdf.timeline_entry('February 27, 2026:', 'I followed up and suggested PayPal as a refund method. The merchant responded: "PayPal works but I\'m just waiting on a transfer to hit. Sorry here in Mexico I mostly live off credit cards. Can u handle a few more days?" I agreed.')

pdf.timeline_entry('March 2026 (present):', 'The merchant has gone silent. No refund has been received. The course has never been delivered.')

# Why This Warrants Exception
pdf.section_title('Why This Warrants an Exception to the 90-Day Dispute Window')

pdf.numbered_point(1, 'The 90-day window expired while I was waiting in good faith for a product the merchant repeatedly promised was coming. As a pre-purchase, the product was not expected to be available at the time of sale.')

pdf.numbered_point(2, 'The merchant himself told me to dispute charges through American Express (October 14, 2025), demonstrating that American Express was the appropriate channel for resolving billing issues with this merchant.')

pdf.numbered_point(3, 'American Express already processed chargebacks on this merchant\'s erroneous charges from the same transaction period (September 2025), establishing a documented record of this merchant\'s billing misconduct.')

pdf.numbered_point(4, 'The merchant publicly promised a January 1, 2026 delivery date in a recorded video and failed to deliver.')

pdf.numbered_point(5, 'The merchant explicitly agreed to a refund in writing on February 23, 2026 and has failed to follow through.')

pdf.numbered_point(6, 'The merchant has demonstrated a pattern of disorganized and potentially deceptive business practices, including: charging my card multiple times in error, operating through numerous Stripe accounts (self-described as "probably Stripe number 28"), collecting payments informally via PayPal and Zelle, and repeatedly making promises he does not keep.')

pdf.numbered_point(7, 'I have never received the product I paid $1,409.99 for. The course was never delivered and, based on the merchant\'s own statements in January 2026, was never even fully recorded.')

# Evidence
pdf.section_title('Attached Evidence')
pdf.body_text('- Exhibit A: Facebook Messenger conversation with Donald Spann (8 pages, chronological) showing the complete timeline of promises, billing errors, delivery delays, and the merchant\'s explicit agreement to issue a refund')
pdf.body_text('- Exhibit B: American Express statement showing original charge ($1,409.99) and five erroneous duplicate charges totaling $6,811.23 from two different merchant names')
pdf.body_text('- Exhibit C: Loom video by Donald Spann dated November 27, 2025, titled "Exciting Updates and Launch Date for the New Course"  -  URL: https://www.loom.com/share/c4fbb6106d814b3aa85224b5ecdf9b2d')
pdf.body_text('- Exhibit D: Transcript of Loom video confirming January 1, 2026 launch promise and informal payment collection practices')

# Resolution
pdf.section_title('Resolution Requested')
pdf.body_text('I respectfully request that American Express grant an exception to the 90-day dispute window and reverse the original charge of $1,409.99. I have been a loyal cardholder for 20 years and have always valued the protection and service that comes with my membership. The merchant has had over six months to deliver the product or issue a refund and has done neither.')

pdf.body_text('I trust that American Express will resolve this matter through its internal complaint process. Should this not be possible, I understand I may escalate to the Ombudsman for Banking Services and Investments (OBSI) and the Financial Consumer Agency of Canada (FCAC).')

pdf.body_text('Thank you for your time and attention to this matter.')

pdf.ln(8)
pdf.body_text('Sincerely,')
pdf.ln(2)
pdf.set_font('Helvetica', 'B', 10)
pdf.cell(0, 5, 'Mike Ziarko', new_x="LMARGIN", new_y="NEXT")
pdf.set_font('Helvetica', '', 10)
pdf.cell(0, 5, 'Card ending 2006', new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 5, '416-272-6683', new_x="LMARGIN", new_y="NEXT")

# --- EXHIBIT A: Messenger Screenshots ---
screenshots = sorted(glob.glob('/Users/harvey/.openclaw/media/inbound/Status_and_Messenger_*'))
if screenshots:
    pdf.add_page()
    pdf.set_font('Helvetica', 'B', 16)
    pdf.cell(0, 10, 'EXHIBIT A', align='C', new_x="LMARGIN", new_y="NEXT")
    pdf.set_font('Helvetica', '', 11)
    pdf.cell(0, 7, 'Facebook Messenger Conversation with Donald Spann', align='C', new_x="LMARGIN", new_y="NEXT")
    pdf.cell(0, 7, 'August 2025 - March 2026', align='C', new_x="LMARGIN", new_y="NEXT")
    pdf.ln(5)
    
    for i, img_path in enumerate(screenshots):
        # Get image dimensions to fit properly
        img = Image.open(img_path)
        w, h = img.size
        # Calculate scaling to fit page width (170mm usable)
        page_w = 170
        aspect = h / w
        img_h = page_w * aspect
        
        # If image would be too tall, scale down
        max_h = 240  # max height in mm
        if img_h > max_h:
            img_h = max_h
            page_w = img_h / aspect
        
        # Check if we need a new page
        if pdf.get_y() + img_h > 270:
            pdf.add_page()
        
        pdf.set_font('Helvetica', 'I', 8)
        pdf.cell(0, 5, f'Screenshot {i+1} of {len(screenshots)}', align='C', new_x="LMARGIN", new_y="NEXT")
        x = (210 - page_w) / 2  # center
        pdf.image(img_path, x=x, w=page_w)
        pdf.ln(5)

# --- EXHIBIT C: Loom Video Reference ---
pdf.add_page()
pdf.set_font('Helvetica', 'B', 16)
pdf.cell(0, 10, 'EXHIBIT C', align='C', new_x="LMARGIN", new_y="NEXT")
pdf.set_font('Helvetica', '', 11)
pdf.cell(0, 7, 'Loom Video by Donald Spann', align='C', new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 7, 'Posted November 27, 2025', align='C', new_x="LMARGIN", new_y="NEXT")
pdf.ln(8)

pdf.set_font('Helvetica', 'B', 11)
pdf.cell(0, 6, 'Video Title:', new_x="LMARGIN", new_y="NEXT")
pdf.set_font('Helvetica', '', 11)
pdf.cell(0, 6, '"Exciting Updates and Launch Date for the New Course"', new_x="LMARGIN", new_y="NEXT")
pdf.ln(3)

pdf.set_font('Helvetica', 'B', 11)
pdf.cell(0, 6, 'URL:', new_x="LMARGIN", new_y="NEXT")
pdf.set_font('Helvetica', '', 10)
pdf.cell(0, 6, 'https://www.loom.com/share/c4fbb6106d814b3aa85224b5ecdf9b2d', new_x="LMARGIN", new_y="NEXT")
pdf.ln(3)

pdf.set_font('Helvetica', 'B', 11)
pdf.cell(0, 6, 'Video Description (from Loom metadata):', new_x="LMARGIN", new_y="NEXT")
pdf.set_font('Helvetica', 'I', 10)
pdf.multi_cell(0, 5, '"Hey everyone, I wanted to give you an update from Puerto Vallarta. I\'m excited to announce that the go-live date for the course is January 1st, and I appreciate your patience during this wait. We\'ve been working hard to expand the content, including new material on voice AI and insights from over a hundred call centers. If you\'re interested in the pre-launch discount, please reach out to me directly. I\'m looking forward to helping you build a successful business model that can improve your life!"')

# --- EXHIBIT D: Video Transcript ---
pdf.add_page()
pdf.set_font('Helvetica', 'B', 16)
pdf.cell(0, 10, 'EXHIBIT D', align='C', new_x="LMARGIN", new_y="NEXT")
pdf.set_font('Helvetica', '', 11)
pdf.cell(0, 7, 'Full Transcript of Loom Video', align='C', new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 7, '"Exciting Updates and Launch Date for the New Course"', align='C', new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 7, 'By Donald Spann - November 27, 2025', align='C', new_x="LMARGIN", new_y="NEXT")
pdf.ln(8)

transcript = """[0:04] Okay, so I'm not quite sure if this video is working because it's not doing it, I'm not connecting it, but, you know, try this anyway.

[0:10] So, uh, you know, it's been a while good to see you guys, uh, hi from Puerto Vallarta, uh, here for a few days.

[0:24] The last few months have been busy. Uh, last time around when I first recorded the original course, uh, you know, all I had going on was recording the course.

[0:34] I recently sold the key virtual. Um, you know, I was doing some investments here in New York, but I wasn't doing anything other than focused on the course.

[0:43] Right now, um, you know, I have dozens of employees, two different companies. And, uh, I'm working in the middle of a fundraise, and which is always fun one time.

[0:54] So, uh, the nice thing is that called Canada. Uh, my call center focused on the cannabis industry. Uh, we're profitable. We're grown. We just, uh, essentially landed. Uh, when I, the first public company I've ever landed for a company I've ever started.

[1:11] Uh, so pretty exciting. Um, and then, you know, our staff and company is, uh, you know, getting off, getting some good momentum as well.

[1:20] Now, with that said, the purpose of this video is to give you an update for the course. So, I finally have like, 100% uh, go live date for the course. And that go live date is gonna be January 1st.

[1:30] Now, for those of you who are very first to be purchasing, this, uh, this kind of course upgrade for the hybrid call center, uh, in, like, July. So, it's been a hell of a wait. You know, I really apologize.

[1:51] Um, you know, I don't want to put out a crappy thing. I don't want to put out a waste of time. And so, it was gonna take some time anyway to get this done.

[1:57] But at least now, I've been recording, um, you know, you know, really, in some way, this is an update for, you know, kind of the original content, but also an expansion, uh, even in that regard.

[2:10] And then of course, uh, we have new material coming in the form of, uh, more technically all the material, you know. But of course now we're talking about voice AI, and our new channel was just something we didn't do before.

[2:35] And so our goal here is to, uh, you know, include some of those perspectives as well, uh, on top of my own, right?

[3:13] Uh, really appreciate the people that have had, you know, a tremendous patience because it's really been all of you. Um, you know, because the course hasn't been out yet, um, we, um, I'm still offering kind of the pre-launch discount.

[3:33] Uh, so just hit me up directly for what that is. And we've been doing it pretty, like, informally than having people. We've sent me money on PayPal or Zell.

[3:46] So, you know, don't think of this as something that the course itself, of course, is gonna be serious. Uh, but this isn't a business, right? So, our goal is to create good content, have you guys be able to have a business model that I'm utilizing, uh, that can really put you guys in a nice situation and live well.

[4:25] If you haven't been getting on a pre-sale discount, but just know January 1st is the date, it's locked in, and, uh, you know, feel free to comment on this post and I appreciate you all."""

pdf.set_font('Helvetica', '', 10)
pdf.multi_cell(0, 5, transcript)

pdf.ln(5)
pdf.set_font('Helvetica', 'B', 10)
pdf.multi_cell(0, 5, 'Key statements highlighted for reference:')
pdf.ln(2)
pdf.set_font('Helvetica', '', 10)
highlights = [
    '"I finally have like, 100% go live date for the course. And that go live date is gonna be January 1st." [1:20]',
    '"It\'s been a hell of a wait. You know, I really apologize." [1:30]',
    '"I\'m still offering kind of the pre-launch discount... we\'ve been doing it pretty informally, having people send me money on PayPal or Zell." [3:13-3:33]',
    '"This isn\'t a business, right?" [3:46]',
    '"January 1st is the date, it\'s locked in." [4:25]',
]
for h in highlights:
    pdf.cell(5, 5, '-')
    pdf.multi_cell(0, 5, h)
    pdf.ln(1)

# Exhibit B: Statement
pdf.add_page()
pdf.set_font('Helvetica', 'B', 16)
pdf.cell(0, 10, 'EXHIBIT B', align='C', new_x="LMARGIN", new_y="NEXT")
pdf.set_font('Helvetica', '', 11)
pdf.cell(0, 7, 'American Express Statement - September 2025', align='C', new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 7, 'Showing Original Charge and Erroneous Duplicate Charges', align='C', new_x="LMARGIN", new_y="NEXT")
pdf.ln(5)

pdf.set_font('Helvetica', '', 9)
pdf.multi_cell(0, 5, 'The following statement page shows the original purchase (Sep 2, HCC INCUBATOR - $1,409.99) and five erroneous duplicate charges from "HYBRID CALL CENTER" totaling $6,811.23 in excess charges. Note the charges appear under two different merchant names, confirming the use of multiple Stripe payment accounts.')
pdf.ln(3)

pdf.set_font('Helvetica', 'B', 9)
pdf.cell(0, 5, 'Relevant charges highlighted:', new_x="LMARGIN", new_y="NEXT")
pdf.set_font('Helvetica', '', 9)
pdf.cell(0, 5, '- Sep 2: HCC INCUBATOR, CHICAGO - $1,409.99 (original purchase)', new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 5, '- Sep 5: HYBRID CALL CENTER, CHICAGO - $1,415.62 (erroneous)', new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 5, '- Sep 6: HYBRID CALL CENTER, CHICAGO - $1,418.60 (erroneous)', new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 5, '- Sep 8: HYBRID CALL CENTER, CHICAGO - $1,418.60 (erroneous)', new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 5, '- Sep 11: HYBRID CALL CENTER, CHICAGO - $1,134.38 (erroneous)', new_x="LMARGIN", new_y="NEXT")
pdf.cell(0, 5, '- Sep 12: HYBRID CALL CENTER, CHICAGO - $1,424.03 (erroneous)', new_x="LMARGIN", new_y="NEXT")
pdf.set_font('Helvetica', 'B', 9)
pdf.cell(0, 5, '  Total erroneous charges: $6,811.23 CAD', new_x="LMARGIN", new_y="NEXT")
pdf.ln(5)

stmt_path = '/Users/harvey/.openclaw/media/inbound/file_115---254a782a-5d4f-4e60-8839-1e4eab9932a1.jpg'
if os.path.exists(stmt_path):
    img = Image.open(stmt_path)
    w, h = img.size
    page_w = 170
    aspect = h / w
    img_h = page_w * aspect
    max_h = 200
    if img_h > max_h:
        img_h = max_h
        page_w = img_h / aspect
    x = (210 - page_w) / 2
    pdf.image(stmt_path, x=x, w=page_w)

# Save
output_path = '/Users/harvey/.openclaw/workspace/Amex_Complaint_Mike_Ziarko.pdf'
pdf.output(output_path)
print(f"PDF saved to: {output_path}")
print(f"Total pages: {pdf.page_no()}")
